Date: Mon Apr 27 16:44:30 2020
Scientist: Ran Yin
Sequencing (Waksman): Dibyendu Kumar
Statistics: Davit Sargsyan
Principal Investigator: Ah-Ng Kong

# Taxonomic Ranks:
# **K**ing **P**hillip **C**an n**O**t **F**ind **G**reen **S**ocks
# * Kingdom                
# * Phylum                    
# * Class                   
# * Order                   
# * Family     
# * Genus     
# * Species  
options(stringsAsFactors = FALSE,
        scipen = 999)
# # Increase mmemory size to 64 Gb----
# invisible(utils::memory.limit(65536))
# str(knitr::opts_chunk$get())
# # NOTE: the below does not work!
# knitr::opts_chunk$set(echo = FALSE, 
#                       message = FALSE,
#                       warning = FALSE,
#                       error = FALSE)
# require(knitr)
# require(kableExtra)
# require(shiny)
require(phyloseq)
Loading required package: phyloseq
require(data.table)
Loading required package: data.table
data.table 1.12.2 using 18 threads (see ?getDTthreads).  Latest news: r-datatable.com
require(ggplot2)
Loading required package: ggplot2
require(plotly)
Loading required package: plotly

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
require(DT)
Loading required package: DT
source("source/functions_may2019.R")

1 Introduction

November 2018 Batch: Nrf2 KO (-/-) Mice
May 2019 Batch: Wild Type Mice

2 Data preprocessing

2.1 Raw Data

FastQ files were downloaded from Dr. Kumar’s DropBox. A total of 60 files (2 per sample, pair-ended) and 2 metadata files were downloaded.

2.2 Script

Data processing scripts (nrf2ubiome_dada2_nov2018_v1.Rmd and nrf2ubiome_dada2_may2019_v1.Rmd) were developed using DADA2 Pipeline Tutorial (1.12) with tips and tricks from the University of Maryland Shool of Medicine Institute for Genome Sciences (IGS) Microbiome Analysis Workshop (April 8-11, 2019). The oresults of the DADA2 scripts (data_nov2018/ps_nov2018.RData and data_may2019/ps_may2019.RData) are explored in this document.

3 Meta data: sample description

# Load data----
# Counts
load("data_nov2018/ps_nov2018.RData")
ps_nov2018 <- copy(ps)
rm(ps)
# Remove "Undetermined" sample
ps_nov2018 <- subset_samples(ps_nov2018, 
                             Name != "Undetermined_S0")
load("data_may2019/ps_may2019.RData")
gc(verbose = FALSE)
          used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells 4012301 214.3    7171411 383.0  6600597 352.6
Vcells 7829899  59.8   14786712 112.9 12233664  93.4
# Taxonomy (use the same one for both batches!)
load("data_may2019/taxa.RData")
taxa <- data.table(seq16s = rownames(taxa),
                   taxa)
# Samples
meta18 <- ps_nov2018@sam_data
datatable(meta18,
          options = list(pageLength = nrow(meta18)),
          caption = "Nrf2 KO (Nov 18) Meta Data")

meta19 <- ps_may2019@sam_data
datatable(meta19,
          options = list(pageLength = nrow(meta19)),
          caption = "WT (May 19) Meta Data")

4 OTUs mapped to Kingdoms, each batch separate

5 Merge the 2 data sets

pss <- merge_phyloseq(ps_nov2018,
                      ps_may2019)
tmp <- pss@sam_data
# Diet
meta <- data.table(Sample = rownames(pss@sam_data),
                   Diet = tmp$Diet)
meta$Diet <- gsub(x = meta$Diet, 
                  pattern = " Control",
                  replacement = "")
meta$Diet[!is.na(tmp$TREATMENT)] <- tmp$TREATMENT[!is.na(tmp$TREATMENT)]
meta$Diet <- gsub(x = meta$Diet,
                  pattern = "Control",
                  replacement = "AIN93M")
meta$Diet[is.na(meta$Diet)] <- "Pooled"
meta$Diet <- factor(meta$Diet,
                    levels = c("AIN93M",
                               "PEITC",
                               "Pooled"))
# Gemotype
meta$Genotype <- "Nrf2 KO"
meta$Genotype[is.na(tmp$Sex)] <- "Wild Type"
meta$Genotype <- factor(meta$Genotype,
                        levels = c("Wild Type",
                                   "Nrf2 KO"))
# Time
meta$Week <- as.numeric(as.character(tmp$Week)) - 4
meta$Week[meta$Genotype == "Wild Type"] <- as.numeric(gsub(x = tmp$WEEK[meta$Genotype == "Wild Type"],
                                                           pattern = "week ",
                                                           replacement = ""))
meta$Week <- paste("Week",
                   meta$Week)
# LAbel correction, as per Ran's email, Tue, Apr 21, 3:29 PM (6 days ago)
meta$Week[meta$Week == "Week 5"] <- "Week 4"
# meta$Week <- factor(meta$Week,
#                     levels = c("Week 0",
#                                "Week 1",
#                                "Week 4",
#                                "Week 5"))
meta$Week <- factor(meta$Week,
                    levels = c("Week 0",
                               "Week 1",
                               "Week 4"))
# Mouse ID
meta$Mouse_Num <- as.numeric(as.character(tmp$MouseNum))
meta$Mouse_Num[meta$Genotype == "Wild Type"] <- as.numeric(substr(x = tmp$SAMPLE_NAME[meta$Genotype == "Wild Type"],
                                                                  start = 3, 
                                                                  stop = 3))
# Cage number
meta$Cage <- as.character(tmp$Cage)
meta$Cage[meta$Genotype == "Wild Type"] <- substr(x = tmp$SAMPLE_NAME[meta$Genotype == "Wild Type"],
                                                  start = 2, 
                                                  stop = 2)
meta$Cage <- factor(meta$Cage)
meta <- data.frame(meta)
rownames(meta) <- meta$Sample
meta
# Edit meta data
sample_data(pss) <- meta
pss@sam_data
Sample Data:        [69 samples by 6 sample variables]:
dim(pss@otu_table@.Data)
[1]    69 17046
# Remove OTU unmapped to Bacteria
ps0 <- subset_taxa(pss, 
                   Kingdom == "Bacteria")
dim(ps0@otu_table@.Data)
[1]    69 16351

6 OTU table (first 10 rows)

7 Total counts per sample (i.e. sequencing depth)

p1 <- ggplot(smpl,
             aes(x = Sample,
                 y = Total,
                 group =Diet,
                 fill = Diet)) +
  facet_wrap(~ Genotype + Week,
             scale = "free") +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete("") +
  scale_y_continuous("Number of Reads") +
  scale_fill_grey("Treatment", 
                  start = 0.1, 
                  end = 1,
                  na.value = "red",
                  aesthetics = "fill") +
  theme_bw() + 
  theme(panel.border = element_blank(), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        # axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/seq_depth_nov2018_may2019.tiff",
     height =6,
     width = 8,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
print(p1)

t2 <- data.table(table(tax_table(ps0)[, "Phylum"],
                                  exclude = NULL))
t2$V1[is.na(t2$V1)] <- "Unknown"
setorder(t2, -N)
t2[, pct := N/sum(N)]
setorder(t2, -N)
colnames(t2) <- c("Phylum",
                  "Number of OTUs",
                  "Percent of OTUs")
datatable(t2,
          rownames = FALSE,
          caption = "Number of Bacterial OTUs by Phylum",
          class = "cell-border stripe",
          options = list(search = FALSE,
                         pageLength = nrow(t2))) %>%
  formatCurrency(columns = 2,
                 currency = "",
                 mark = ",",
                 digits = 0) %>%
  formatPercentage(columns = 3,
                   digits = 2)

ps1 <- subset_taxa(ps0, 
                   !is.na(Phylum))
dim(ps1@otu_table@.Data)
[1]    69 15919

8 Remove Phylum

Remove:
1. Unmapped OTUs (“Unknown”).
2. Cyanobacteria: aerobic, photosynthesizing bacteria that probably got into the sample through food.
NOTE: Chloroflexi might be ok.

ps0 <- subset_taxa(ps0,
                   (!(Phylum %in% c("Unknown",
                                   "Cyanobacteria"))))

9 Richness (Alpha diversity)

Shannon index (aka Shannon enthrophy) is calculated as:
H’ = -sum(1 to R)p(i)ln(p(i)) When there is exactly 1 type of data (e.g. a single species in the sample), H’=0. The opposite scenario is when there are R>1 species present in the sample in the exact same amounts and H’=ln(R).

Shannon’s diversity index was calculated for each sample and ploted over time.

shannon.ndx <- estimate_richness(ps0,
                                 measures = "Shannon")
shannon.ndx <- data.table(Sample = rownames(shannon.ndx),
                          shannon.ndx)
smpl <- merge(smpl,
              shannon.ndx,
              by = "Sample")
p1 <- ggplot(smpl,
             aes(x = Total,
                 y = Shannon,
                 fill = Genotype,
                 shape = Week)) +
  geom_point(size = 2) +
  scale_shape_manual(breaks = unique(smpl$Week),
                     values = 21:24)
tiff(filename = "tmp/shannon_vs_depth_nov18_may19.tiff",
     height = 5,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)

Even though estimate_richness function does not adjust for the sequencing depth, there is no correlation between the index and the sample’s sequecing depth. Proceed with the comparison.

10 Shannon idex over time

p1 <- plot_richness(ps0,
                    x = "Week", 
                    measures = "Shannon") +
  facet_wrap(~ Genotype,
             scale = "free_x") +
  geom_line(aes(group = paste0(Diet,
                               Cage,
                               Mouse_Num)),
            color = "black") +
  geom_point(aes(fill = Diet),
             shape = 21,
             size = 3,
             color = "black") +
  scale_x_discrete("") +
  theme(axis.text.x = element_text(angle = 30,
                                   hjust = 1,
                                   vjust = 1))
ggplotly(p = p1,
         tooltip = c("Mouse_Num",
                     "value"))

p1 <- p1 + 
  scale_fill_discrete("") +
  theme(legend.position = "top")
tiff(filename = "tmp/shannon_nov18_may19.tiff",
     height = 5,
     width = 8,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()

The plot above suggests that the largest differences in alpha diversity (as measured by Shannon’s index) are in genotype. THis was also confirmed in the 3rd study (September 2019 batch)

11 Average Shannon Index

# Average shannon index by treatment group
tmp <- data.table(copy(smpl))
tmp[, mu := mean(Shannon),
    by = list(Diet,
              Genotype,
              Week)]
tmp[, sem := sd(Shannon)/sqrt(.N),
    by = list(Diet,
              Genotype,
              Week)]
tmp <- unique(tmp[, c("Diet",
                      "Genotype",
                      "Week",
                      "mu",
                      "sem")])
p1 <- ggplot(tmp,
             aes(x = Week,
                 y = mu,
                 ymin = mu - sem,
                 ymax = mu + sem,
                 fill = Diet,
                 group = Diet)) +
  facet_wrap(~ Genotype,
             scale = "free_x") +
  geom_errorbar(position = position_dodge(0.3),
                width = 0.4) +
  geom_line(position = position_dodge(0.3)) +
  geom_point(size = 3,
             shape = 21,
             position = position_dodge(0.3)) +
  scale_x_discrete("") +
  scale_y_continuous("Shannon Index") +
  scale_fill_grey("Treatment", 
                  start = 0, 
                  end = 1,
                  na.value = "red",
                  aesthetics = "fill") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        # panel.border = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/avg_shannon_nov18_may19.tiff",
     height = 4,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
print(p1)

NOTE: cannot test diet effect because of unassigend pooled samples in the KO mice. For the same reason, cannot use mixed effects model on the whole data set. At best, testing genotype and time trend by assuming Week 4 in WT = Week 5 in KO.

smpl$Timepoint <- as.numeric(smpl$Week)
smpl$Timepoint[smpl$Timepoint == 4] <- 3
m1 <- lm(Shannon ~ Timepoint*Genotype,
         data = smpl)
summary(m1)

Call:
lm(formula = Shannon ~ Timepoint * Genotype, data = smpl)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.45931 -0.09344  0.02849  0.08560  0.34790 

Coefficients:
                          Estimate Std. Error t value            Pr(>|t|)    
(Intercept)                6.55295    0.08207  79.842 <0.0000000000000002 ***
Timepoint                  0.04053    0.03799   1.067              0.2900    
GenotypeNrf2 KO            0.35620    0.13511   2.636              0.0105 *  
Timepoint:GenotypeNrf2 KO  0.09221    0.05778   1.596              0.1154    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1699 on 65 degrees of freedom
Multiple R-squared:  0.7687,    Adjusted R-squared:  0.7581 
F-statistic: 72.02 on 3 and 65 DF,  p-value: < 0.00000000000000022

No significant time trend; significantly higher alpha diversity in the Nrf2 KO mice. This is possibly a batch effect but we observed same trend in Study 3 (Crabbery and PEITC with both genotypes in the same study).

12 Bacteriotides vs. Firmicutes

counts_p <- counts_by_tax_rank(dt1 = otu,
                               aggr_by = "Phylum")
fb <- t(counts_p[Phylum %in% c("Bacteroidetes",
                               "Firmicutes"), -1])
fb <- data.table(Sample = rownames(fb),
                 Bacteroidetes = fb[, 1],
                 Firmicutes = fb[, 2])
fb <- data.table(merge(meta,
            fb,
            by = "Sample"))
lims <- log2(range(c(fb$Bacteroidetes,
                     fb$Firmicutes)))
p1 <- ggplot(fb,
             aes(x = log2(Bacteroidetes),
                 y = log2(Firmicutes),
                 fill = Genotype)) +
  geom_point(size = 2,
             color = "black",
             shape = 21) +
  geom_abline(slope = 1,
              intercept = 0,
              linetype = "dashed") +
  scale_x_continuous(limits = lims) +
  scale_y_continuous(limits = lims) +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())
  
p2 <- ggplot(fb,
             aes(x = log2(Bacteroidetes),
                 y = log2(Firmicutes),
                 fill = Week)) +
  geom_point(size = 2,
             color = "black",
             shape = 21) +
  geom_abline(slope = 1,
              intercept = 0,
              linetype = "dashed") +
  scale_x_continuous(limits = lims) +
  scale_y_continuous(limits = lims) +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())
p3 <- ggplot(fb,
             aes(x = log2(Bacteroidetes),
                 y = log2(Firmicutes),
                 fill = Diet)) +
  geom_point(size = 2,
             color = "black",
             shape = 21) +
  geom_abline(slope = 1,
              intercept = 0,
              linetype = "dashed") +
  scale_x_continuous(limits = lims) +
  scale_y_continuous(limits = lims) +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())
p4 <- ggplot(fb,
             aes(x = Week,
                 y = Bacteroidetes/Firmicutes,
                 fill = Diet,
                 group = paste0(Diet,
                               Cage,
                               Mouse_Num))) +
  facet_grid(~ Genotype,
             scale = "free_x") +
  geom_hline(yintercept = 1,
             linetype = "dashed") +
  geom_line(position = position_dodge(0.3)) +
  geom_point(size = 2,
             color = "black",
             shape = 21,
             position = position_dodge(0.3))  +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        # panel.border = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        # axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/bact_vs_firm_nov18_may19.tiff",
     height = 6,
     width =8,
     units = "in",
     res = 600,
     compression = "lzw+p")
gridExtra::grid.arrange(p1, p2, p3, p4)
graphics.off()
gridExtra::grid.arrange(p1, p2, p3, p4)

fb[, B_F := Bacteroidetes/Firmicutes]
fb[, log2_B_F := log2(B_F)]
m1 <- lm(log2_B_F ~ 0 + Week*Diet,
         data = droplevels(fb[Genotype == "Wild Type", ]))
s1 <- summary(m1)
ci1 <- confint(m1)
t1 <- data.table(Term = rownames(s1$coefficients),
                 Ratio = round(2^s1$coefficients[, 1], 3),
                 `95% C.I.L.L.` = round(2^ci1[, 1], 3),
                 `95% C.I.U.L.` = round(2^ci1[, 2], 3),
                 `p-Value` = round(s1$coefficients[, 4], 3),
                 Sign = "")
t1$Sign[t1$`p-Value` < 0.05] <- "*"
t1$Sign[t1$`p-Value` < 0.01] <- "**"
t1$`p-Value`[t1$`p-Value` < 0.001] <- "<0.001"
datatable(t1,
          rownames = FALSE,
          class = "cell-border stripe",
          caption = "Wild Type")

m2 <- lm(log2_B_F ~ 0 + Week*Diet,
         data = droplevels(fb[Genotype == "Nrf2 KO", ]))
s2 <- summary(m2)
ci2 <- confint(m2)
ci2 <- ci2[!is.na(ci2[, 1]),]
t2 <- data.table(Term = rownames(s2$coefficients),
                 Ratio = round(2^s2$coefficients[, 1], 3),
                 `95% C.I.L.L.` = round(2^ci2[, 1], 3),
                 `95% C.I.U.L.` = round(2^ci2[, 2], 3),
                 `p-Value` = round(s2$coefficients[, 4], 3),
                 Sign = "")
t2$Sign[t2$`p-Value` < 0.05] <- "*"
t2$Sign[t2$`p-Value` < 0.01] <- "**"
t2$`p-Value`[t2$`p-Value` < 0.001] <- "<0.001"
datatable(t2,
          rownames = FALSE,
          class = "cell-border stripe",
          caption = "Nrf2 KO")

fb[, mu := mean(Bacteroidetes/Firmicutes),
   by = c("Diet",
          "Genotype",
          "Week")]
fb[, sem := sd(Bacteroidetes/Firmicutes)/sqrt(.N),
   by = c("Diet",
          "Genotype",
          "Week")]
mufb <- unique(fb[, c("Diet",
                      "Genotype",
                      "Week",
                      "mu",
                      "sem")])
p5 <- ggplot(mufb,
             aes(x = Week,
                 y = mu,
                 ymin = mu - sem,
                 ymax = mu + sem,
                 fill = Diet,
                 group = Diet)) +
  facet_wrap(~ Genotype,
             scale = "free_x") +
  geom_hline(yintercept = 1,
             linetype = "dashed") +
  geom_errorbar(position = position_dodge(0.3),
                width = 0.4) +
  geom_line(position = position_dodge(0.3)) +
  geom_point(size = 3,
             shape = 21,
             position = position_dodge(0.3)) +
  scale_x_discrete("") +
  scale_y_continuous("Bacteroidetes/Firmicutes") +
  scale_fill_grey("Treatment", 
                  start = 0, 
                  end = 1,
                  na.value = "red",
                  aesthetics = "fill") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        # panel.border = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        # axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/avg_bact_firm_nov18_may19.tiff",
     height = 4,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p5)
graphics.off()
print(p5)

mufb[, est := paste0(round(mu, 2),
                     "(",
                     round(sem, 2),
                     ")")]
t1 <- dcast.data.table(mufb,
                       Genotype + Diet ~ Week,
                       value.var = "est")
datatable(t1,
          rownames = FALSE,
          class = "cell-border stripe",
          caption = "Average Ratio and SD of Bacteroidetes and Firmicutes",
          options = list(search = FALSE,
                         pageLength = nrow(t1)))

13 Alternative Fig 7

tiff(filename = "tmp/fig7_alt_bact_vs_firm_nov18_may19.tiff",
     height = 6,
     width =8,
     units = "in",
     res = 600,
     compression = "lzw+p")
gridExtra::grid.arrange(p1, p2, p3, p5)
graphics.off()
gridExtra::grid.arrange(p1, p2, p3, p5)

14 Update OTU table: excuded unknown phylum and Cyanobacteria

otu <- data.table(ps0@tax_table@.Data,
                  t(ps0@otu_table@.Data))
# Remove Species mapping'
otu$Species <- NULL
dim(otu)
[1] 16221    75

15 1. Phylum

15.1 Counts at Phylum level

15.2 Relative abundance (%) at Phylum level

15.3 PCA at Phylum level

dt_pca <- t(ra_p[, 2:ncol(ra_p)])
colnames(dt_pca) <- ra_p$Phylum
dt_pca_p <- data.table(Sample = rownames(dt_pca),
                       dt_pca)
dt_pca_p <- merge(smpl,
                  dt_pca_p,
                  by = "Sample")
# Keep only the phylum with non-zero counts
tmp <- dt_pca_p[, 10:ncol(dt_pca_p)]
keep_p <- colnames(tmp)[colSums(tmp) > 0]
dt_pca <- dt_pca[, keep_p]
# m1 <- prcomp(dt_pca,
#              center = TRUE,
#              scale. = TRUE)
# m1 <- prcomp(dt_pca,
#              center = FALSE,
#              scale. = FALSE)
m1 <- prcomp(dt_pca,
             center = TRUE,
             scale. = FALSE)
summary(m1)
Importance of components:
                          PC1     PC2     PC3     PC4     PC5      PC6      PC7       PC8       PC9       PC10
Standard deviation     0.1016 0.07982 0.05398 0.03765 0.01000 0.008812 0.002823 0.0004897 0.0001899 0.00008382
Proportion of Variance 0.4864 0.30051 0.13743 0.06688 0.00472 0.003660 0.000380 0.0000100 0.0000000 0.00000000
Cumulative Proportion  0.4864 0.78693 0.92435 0.99123 0.99595 0.999610 0.999990 1.0000000 1.0000000 1.00000000
                             PC11      PC12       PC13
Standard deviation     0.00003105 0.0000258 0.00002073
Proportion of Variance 0.00000000 0.0000000 0.00000000
Cumulative Proportion  1.00000000 1.0000000 1.00000000
# Select PC-s to pliot (PC1 & PC2)
choices <- 1:2
# Add meta data
dt.scr <- data.table(m1$x[, choices])
dt.scr$Sample <- rownames(m1$x)
dt.scr <- merge(smpl,
                dt.scr,
                by = "Sample")
dt.scr
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
dt.rot
dt.load <- melt.data.table(dt.rot,
                           id.vars = "feat",
                           measure.vars = 1:2,
                           variable.name = "pc",
                           value.name = "loading")
dt.load$feat <- factor(dt.load$feat,
                       levels = unique(dt.load$feat))
# Plot loadings
p0 <- ggplot(data = dt.load,
             aes(x = feat,
                 y = loading)) +
  facet_wrap(~ pc,
             nrow = 2) +
  geom_bar(stat = "identity") +
  ggtitle("PC Loadings") +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1))
p0
tiff(filename = "tmp/pc.1.2_loadings_phylum.tiff",
     height = 5,
     width = 6,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p0)
graphics.off()
print(p0)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[1:2], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))
u.axis.labs
[1] "PC1 (48.6% explained var.)" "PC2 (30.1% explained var.)"
cntr <- data.table(aggregate(x = dt.scr$PC1,
                             by = list(dt.scr$Genotype),
                             FUN = "mean"),
                   aggregate(x = dt.scr$PC2,
                             by = list(dt.scr$Genotype),
                             FUN = "mean")$x)
colnames(cntr) <- c("Genotype",
                    "PC1",
                    "PC2")
# Based on Figure p0, keep only a few variables with high loadings in PC1 and PC2----
dt.rot[, rating:= (PC1)^2 + (PC2)^2]
setorder(dt.rot, -rating)
# Select top 5
dt.rot <- dt.rot[1:5, ]
# var.keep.ndx <- which(dt.rot$feat %in% c(...))
# Or select all
# var.keep.ndx <- 3:ncol(dt1)
# Use dt.rot[var.keep.ndx,] and dt.rot$feat[var.keep.ndx]
p1 <- ggplot(data = dt.rot,
             aes(x = PC1,
                 y = PC2)) +
  # coord_equal() +
  geom_point(data = dt.scr,
             aes(fill = Genotype,
                 shape = factor(Timepoint)),
             size = 3,
             alpha = 0.5) +
  geom_segment(aes(x = 0,
                   y = 0,
                   xend = 0.2*PC1,
                   yend = 0.2*PC2),
               arrow = arrow(length = unit(1/2, 'picas')),
               # size = 1, 
               color = "black") +
  geom_text(aes(x = 0.22*PC1,
                y = 0.22*PC2,
                label = dt.rot$feat),
            # size = 5,
            hjust = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  scale_fill_manual(name = "Group",
                    breaks = c("Wild Type",
                               "Nrf2 KO"),
                    values = c("red",
                               "blue")) +
  scale_shape_manual(breaks = 1:3,
                     values = 21:23) +
  geom_label(data = cntr,
             aes(x = PC1,
                 y = PC2,
                 label = Genotype,
                 colour = Genotype),
             alpha = 0.5,
             size = 3) +
  scale_color_manual(guide = FALSE,
                     breaks = c("Wild Type",
                                "Nrf2 KO"),
                     values = c("red",
                                "blue")) +
  ggtitle("") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
tiff(filename = "tmp/phylum_biplot_grp.tiff",
     height = 7,
     width = 7,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)
geom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issues

# Generic biplot
biplot(m1)

16 2. Class

16.1 Counts at Class level

16.2 Relative abundance (%) at Class level

16.3 PCA at Class level

dt_pca <- t(ra_c[, 2:ncol(ra_c)])
colnames(dt_pca) <- ra_c$Class
dt_pca_c <- data.table(Sample = rownames(dt_pca),
                       dt_pca)
dt_pca_c <- merge(smpl,
                  dt_pca_c,
                  by = "Sample")
# Keep only the Class with non-zero counts
tmp <- dt_pca_c[, 10:ncol(dt_pca_c)]
keep_c <- colnames(tmp)[colSums(tmp) > 0]
dt_pca <- dt_pca[, keep_c]
m1 <- prcomp(dt_pca,
             center = TRUE,
             scale. = FALSE)
summary(m1)
Importance of components:
                           PC1     PC2    PC3     PC4     PC5     PC6     PC7      PC8      PC9     PC10     PC11
Standard deviation     0.08999 0.07999 0.0740 0.05046 0.03517 0.02037 0.01466 0.009891 0.008728 0.007865 0.005555
Proportion of Variance 0.32837 0.25949 0.2220 0.10327 0.05015 0.01682 0.00872 0.003970 0.003090 0.002510 0.001250
Cumulative Proportion  0.32837 0.58786 0.8099 0.91318 0.96333 0.98016 0.98887 0.992840 0.995930 0.998440 0.999690
                          PC12     PC13      PC14      PC15       PC16      PC17      PC18       PC19       PC20
Standard deviation     0.00265 0.000615 0.0004527 0.0001791 0.00008448 0.0000719 0.0000276 0.00002248 0.00002123
Proportion of Variance 0.00028 0.000020 0.0000100 0.0000000 0.00000000 0.0000000 0.0000000 0.00000000 0.00000000
Cumulative Proportion  0.99997 0.999990 1.0000000 1.0000000 1.00000000 1.0000000 1.0000000 1.00000000 1.00000000
                             PC21       PC22       PC23        PC24
Standard deviation     0.00001378 0.00001094 0.00001006 0.000009136
Proportion of Variance 0.00000000 0.00000000 0.00000000 0.000000000
Cumulative Proportion  1.00000000 1.00000000 1.00000000 1.000000000
# Select PC-s to pliot (PC1 & PC2)
choices <- 1:2
# Add meta data
dt.scr <- data.table(m1$x[, choices])
dt.scr$Sample <- rownames(m1$x)
dt.scr <- merge(smpl,
                dt.scr,
                by = "Sample")
dt.scr
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
dt.rot
dt.load <- melt.data.table(dt.rot,
                           id.vars = "feat",
                           measure.vars = 1:2,
                           variable.name = "pc",
                           value.name = "loading")
dt.load$feat <- factor(dt.load$feat,
                       levels = unique(dt.load$feat))
# Plot loadings
p0 <- ggplot(data = dt.load,
             aes(x = feat,
                 y = loading)) +
  facet_wrap(~ pc,
             nrow = 2) +
  geom_bar(stat = "identity") +
  ggtitle("PC Loadings") +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1))
p0
tiff(filename = "tmp/pc.1.2_loadings_Class.tiff",
     height = 5,
     width = 6,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p0)
graphics.off()
print(p0)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[1:2], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))
u.axis.labs
[1] "PC1 (32.8% explained var.)" "PC2 (25.9% explained var.)"
cntr <- data.table(aggregate(x = dt.scr$PC1,
                             by = list(dt.scr$Genotype),
                             FUN = "mean"),
                   aggregate(x = dt.scr$PC2,
                             by = list(dt.scr$Genotype),
                             FUN = "mean")$x)
colnames(cntr) <- c("Genotype",
                    "PC1",
                    "PC2")
# Based on Figure p0, keep only a few variables with high loadings in PC1 and PC2----
dt.rot[, rating:= (PC1)^2 + (PC2)^2]
setorder(dt.rot, -rating)
# Select top 8
dt.rot <- dt.rot[1:8, ]
# var.keep.ndx <- which(dt.rot$feat %in% c(...))
# Or select all
# var.keep.ndx <- 3:ncol(dt1)
# Use dt.rot[var.keep.ndx,] and dt.rot$feat[var.keep.ndx]
p1 <- ggplot(data = dt.rot,
             aes(x = PC1,
                 y = PC2)) +
  geom_point(data = dt.scr,
             aes(fill = Genotype,
                 shape = factor(Timepoint)),
             size = 3,
             alpha = 0.5) +
  geom_segment(aes(x = 0,
                   y = 0,
                   xend = 0.2*PC1,
                   yend = 0.2*PC2),
               arrow = arrow(length = unit(1/2, 'picas')),
               # size = 1, 
               color = "black") +
  geom_text(aes(x = 0.22*PC1,
                y = 0.22*PC2,
                label = dt.rot$feat),
            # size = 5,
            hjust = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  scale_fill_manual(name = "Group",
                    breaks = c("Wild Type",
                               "Nrf2 KO"),
                    values = c("red",
                               "blue")) +
  scale_shape_manual(breaks = 1:3,
                     values = 21:23) +
  geom_label(data = cntr,
             aes(x = PC1,
                 y = PC2,
                 label = Genotype,
                 colour = Genotype),
             alpha = 0.5,
             size = 3) +
  scale_color_manual(guide = FALSE,
                     breaks = c("Wild Type",
                                "Nrf2 KO"),
                     values = c("red",
                                "blue")) +
  ggtitle("") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
tiff(filename = "tmp/class_biplot_gen.tiff",
     height = 7,
     width = 7,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)
geom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issues

# Generic biplot
biplot(m1)

16.4 3. Order

16.5 4. Family

17 5. Genus

17.1 Counts at Genus level

17.2 Relative abundance (%) at Genus level

17.3 PCA at Genus level

dt_pca <- t(ra_g[, 2:ncol(ra_g)])
colnames(dt_pca) <- ra_g$Genus
dt_pca_g <- data.table(Sample = rownames(dt_pca),
                       dt_pca)
dt_pca_g <- merge(smpl,
                  dt_pca_g,
                  by = "Sample")
# Keep only the Genus with non-zero counts
tmp <- dt_pca_g[, 10:ncol(dt_pca_g)]
keep_g <- colnames(tmp)[colSums(tmp) > 0]
dt_pca <- dt_pca[, keep_g]
m1 <- prcomp(dt_pca,
             center = TRUE,
             scale. = FALSE)
summary(m1)
Importance of components:
                          PC1     PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10    PC11
Standard deviation     0.1561 0.07993 0.07342 0.06674 0.05499 0.04364 0.03276 0.02879 0.02722 0.02502 0.02370
Proportion of Variance 0.4792 0.12568 0.10605 0.08761 0.05948 0.03746 0.02112 0.01631 0.01457 0.01232 0.01105
Cumulative Proportion  0.4792 0.60492 0.71097 0.79858 0.85806 0.89552 0.91663 0.93294 0.94752 0.95983 0.97088
                          PC12    PC13    PC14    PC15    PC16    PC17     PC18     PC19     PC20     PC21
Standard deviation     0.01666 0.01491 0.01453 0.01219 0.01067 0.01000 0.009643 0.008103 0.006794 0.006453
Proportion of Variance 0.00546 0.00437 0.00415 0.00292 0.00224 0.00197 0.001830 0.001290 0.000910 0.000820
Cumulative Proportion  0.97634 0.98072 0.98487 0.98779 0.99003 0.99200 0.993830 0.995120 0.996030 0.996850
                           PC22     PC23     PC24     PC25    PC26     PC27     PC28    PC29     PC30     PC31
Standard deviation     0.005544 0.005349 0.004051 0.003882 0.00355 0.003155 0.002829 0.00269 0.002344 0.002183
Proportion of Variance 0.000600 0.000560 0.000320 0.000300 0.00025 0.000200 0.000160 0.00014 0.000110 0.000090
Cumulative Proportion  0.997450 0.998010 0.998340 0.998630 0.99888 0.999080 0.999230 0.99938 0.999480 0.999580
                           PC32     PC33    PC34     PC35    PC36     PC37     PC38      PC39      PC40      PC41
Standard deviation     0.001933 0.001904 0.00180 0.001411 0.00123 0.001175 0.001096 0.0009692 0.0008116 0.0007119
Proportion of Variance 0.000070 0.000070 0.00006 0.000040 0.00003 0.000030 0.000020 0.0000200 0.0000100 0.0000100
Cumulative Proportion  0.999650 0.999720 0.99979 0.999830 0.99986 0.999880 0.999910 0.9999200 0.9999400 0.9999500
                            PC42      PC43      PC44      PC45      PC46      PC47      PC48      PC49      PC50
Standard deviation     0.0006493 0.0005688 0.0005378 0.0004891 0.0004791 0.0004499 0.0003972 0.0003618 0.0003308
Proportion of Variance 0.0000100 0.0000100 0.0000100 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
Cumulative Proportion  0.9999600 0.9999600 0.9999700 0.9999700 0.9999800 0.9999800 0.9999800 0.9999900 0.9999900
                            PC51      PC52      PC53      PC54      PC55      PC56      PC57      PC58      PC59
Standard deviation     0.0003232 0.0002766 0.0002682 0.0002355 0.0002136 0.0002006 0.0001936 0.0001866 0.0001584
Proportion of Variance 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
Cumulative Proportion  0.9999900 0.9999900 0.9999900 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
                            PC60      PC61      PC62       PC63       PC64       PC65       PC66       PC67
Standard deviation     0.0001441 0.0001155 0.0001064 0.00009134 0.00008498 0.00006457 0.00005041 0.00004638
Proportion of Variance 0.0000000 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
Cumulative Proportion  1.0000000 1.0000000 1.0000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000
                             PC68                   PC69
Standard deviation     0.00003256 0.00000000000000001228
Proportion of Variance 0.00000000 0.00000000000000000000
Cumulative Proportion  1.00000000 1.00000000000000000000
# Select PC-s to pliot (PC1 & PC2)
choices <- 1:2
# Add meta data
dt.scr <- data.table(m1$x[, choices])
dt.scr$Sample <- rownames(m1$x)
dt.scr <- merge(smpl,
                dt.scr,
                by = "Sample")
dt.scr
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
dt.rot
dt.load <- melt.data.table(dt.rot,
                           id.vars = "feat",
                           measure.vars = 1:2,
                           variable.name = "pc",
                           value.name = "loading")
dt.load$feat <- factor(dt.load$feat,
                       levels = unique(dt.load$feat))
# Plot loadings
p0 <- ggplot(data = dt.load,
             aes(x = feat,
                 y = loading)) +
  facet_wrap(~ pc,
             nrow = 2) +
  geom_bar(stat = "identity") +
  ggtitle("PC Loadings") +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1))
p0
tiff(filename = "tmp/pc.1.2_loadings_genus.tiff",
     height = 5,
     width = 6,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p0)
graphics.off()
print(p0)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[1:2], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))
u.axis.labs
[1] "PC1 (47.9% explained var.)" "PC2 (12.6% explained var.)"
cntr <- data.table(aggregate(x = dt.scr$PC1,
                             by = list(dt.scr$Genotype),
                             FUN = "mean"),
                   aggregate(x = dt.scr$PC2,
                             by = list(dt.scr$Genotype),
                             FUN = "mean")$x)
colnames(cntr) <- c("Genotype",
                    "PC1",
                    "PC2")
# Based on Figure p0, keep only a few variables with high loadings in PC1 and PC2----
dt.rot[, rating:= (PC1)^2 + (PC2)^2]
setorder(dt.rot, -rating)
# Select top 9
dt.rot <- dt.rot[1:9, ]
# var.keep.ndx <- which(dt.rot$feat %in% c(...))
# Or select all
# var.keep.ndx <- 3:ncol(dt1)
# Use dt.rot[var.keep.ndx,] and dt.rot$feat[var.keep.ndx]
p1 <- ggplot(data = dt.rot,
             aes(x = PC1,
                 y = PC2)) +
  geom_point(data = dt.scr,
             aes(fill = Genotype,
                 shape = factor(Timepoint)),
             size = 3,
             alpha = 0.5) +
  geom_segment(aes(x = 0,
                   y = 0,
                   xend = 0.2*PC1,
                   yend = 0.2*PC2),
               arrow = arrow(length = unit(1/2, 'picas')),
               # size = 1, 
               color = "black") +
  geom_text(aes(x = 0.22*PC1,
                y = 0.22*PC2,
                label = dt.rot$feat),
            # size = 5,
            hjust = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  scale_fill_manual(name = "Group",
                    breaks = c("Wild Type",
                               "Nrf2 KO"),
                    values = c("red",
                               "blue")) +
  scale_shape_manual(breaks = 1:3,
                     values = 21:23) +
  geom_label(data = cntr,
             aes(x = PC1,
                 y = PC2,
                 label = Genotype,
                 colour = Genotype),
             alpha = 0.5,
             size = 3) +
  scale_color_manual(guide = FALSE,
                     breaks = c("Wild Type",
                                "Nrf2 KO"),
                     values = c("red",
                                "blue")) +
  ggtitle("") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
tiff(filename = "tmp/genus_biplot_gen.tiff",
     height = 7,
     width = 7,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)
geom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issues

# Generic biplot
biplot(m1)

cntr <- data.table(aggregate(x = dt.scr$PC1,
                             by = list(dt.scr$Diet),
                             FUN = "mean"),
                   aggregate(x = dt.scr$PC2,
                             by = list(dt.scr$Diet),
                             FUN = "mean")$x)
colnames(cntr) <- c("Diet",
                    "PC1",
                    "PC2")
p2 <- ggplot(data = dt.rot,
             aes(x = PC1,
                 y = PC2)) +
  geom_point(data = dt.scr,
             aes(fill = Diet,
                 shape = factor(Timepoint)),
             size = 3,
             alpha = 0.5) +
  geom_segment(aes(x = 0,
                   y = 0,
                   xend = 0.2*PC1,
                   yend = 0.2*PC2),
               arrow = arrow(length = unit(1/2, 'picas')),
               # size = 1, 
               color = "black") +
  geom_text(aes(x = 0.22*PC1,
                y = 0.22*PC2,
                label = dt.rot$feat),
            # size = 5,
            hjust = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  scale_fill_manual(name = "Group",
                    breaks = c("AIN93M",
                               "PEITC",
                               "Pooled"),
                    values = c("red",
                               "blue",
                               "black")) +
  scale_shape_manual(breaks = 1:3,
                     values = 21:23) +
  geom_label(data = cntr,
             aes(x = PC1,
                 y = PC2,
                 label = Diet,
                 colour = Diet),
             alpha = 0.5,
             size = 3) +
  scale_color_manual(guide = FALSE,
                     breaks = c("AIN93M",
                                "PEITC",
                                "Pooled"),
                     values = c("red",
                                "blue",
                                "black")) +
  ggtitle("") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
tiff(filename = "tmp/genus_biplot_diet.tiff",
     height = 7,
     width = 7,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p2)
graphics.off()
ggplotly(p2)
geom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issues

18 Session Information

sessionInfo()
R version 3.5.0 (2018-04-23)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux Server 7.5 (Maipo)

Matrix products: default
BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] DT_0.6            plotly_4.9.0      ggplot2_3.2.0     data.table_1.12.2 phyloseq_1.26.1  

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.1          ape_5.3             lattice_0.20-35     tidyr_0.8.3         Biostrings_2.50.2  
 [6] assertthat_0.2.1    digest_0.6.19       foreach_1.4.4       mime_0.6            R6_2.4.0           
[11] plyr_1.8.4          stats4_3.5.0        httr_1.4.0          pillar_1.4.0        zlibbioc_1.28.0    
[16] rlang_0.4.0         lazyeval_0.2.2      rstudioapi_0.10     vegan_2.5-5         S4Vectors_0.20.1   
[21] Matrix_1.2-14       labeling_0.3        splines_3.5.0       stringr_1.4.0       htmlwidgets_1.3    
[26] igraph_1.2.4.1      munsell_0.5.0       shiny_1.3.2         compiler_3.5.0      httpuv_1.5.1       
[31] xfun_0.7            pkgconfig_2.0.2     BiocGenerics_0.28.0 multtest_2.38.0     mgcv_1.8-23        
[36] htmltools_0.3.6     biomformat_1.10.1   tidyselect_0.2.5    gridExtra_2.3       tibble_2.1.3       
[41] IRanges_2.16.0      codetools_0.2-15    permute_0.9-5       viridisLite_0.3.0   crayon_1.3.4       
[46] dplyr_0.8.1         withr_2.1.2         later_0.8.0         MASS_7.3-49         grid_3.5.0         
[51] nlme_3.1-137        jsonlite_1.6        xtable_1.8-4        gtable_0.3.0        lifecycle_0.1.0    
[56] magrittr_1.5        scales_1.1.0        stringi_1.4.3       farver_2.0.3        XVector_0.22.0     
[61] reshape2_1.4.3      promises_1.0.1      Rhdf5lib_1.4.3      iterators_1.0.10    tools_3.5.0        
[66] ade4_1.7-13         Biobase_2.42.0      glue_1.3.1          purrr_0.3.2         crosstalk_1.0.0    
[71] parallel_3.5.0      survival_2.41-3     yaml_2.2.0          colorspace_1.4-1    rhdf5_2.26.2       
[76] cluster_2.0.7-1     knitr_1.23         
LS0tCnRpdGxlOiAiTnJmMiBCTDYgV2lsZC1UeXBlIChXVCkgUEVJVEMgMTZTIE1pY3JvYmlvbWUgRGF0YSBWaXN1YWxpemF0aW9uIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCkRhdGU6IGByIGRhdGUoKWAgICAgIApTY2llbnRpc3Q6IFtSYW4gWWluXShtYWlsdG86cnkxNDdAc2NhcmxldG1haWwucnV0Z2Vycy5lZHUpICAgICAgClNlcXVlbmNpbmcgKFdha3NtYW4pOiBbRGlieWVuZHUgS3VtYXJdKG1haWx0bzpka0B3YWtzbWFuLnJ1dGdlcnMuZWR1KSAgICAgIApTdGF0aXN0aWNzOiBbRGF2aXQgU2FyZ3N5YW5dKG1haWx0bzpzYXJnZGF2aWRAZ21haWwuY29tKSAgICAgIApQcmluY2lwYWwgSW52ZXN0aWdhdG9yOiBbQWgtTmcgS29uZ10obWFpbHRvOmtvbmd0QHBoYXJtYWN5LnJ1dGdlcnMuZWR1KSAKCmBgYHt9CiMgVGF4b25vbWljIFJhbmtzOgojICoqSyoqaW5nICoqUCoqaGlsbGlwICoqQyoqYW4gbioqTyoqdCAqKkYqKmluZCAqKkcqKnJlZW4gKipTKipvY2tzCiMgKiBLaW5nZG9tICAgICAgICAgICAgICAgIAojICogUGh5bHVtICAgICAgICAgICAgICAgICAgICAKIyAqIENsYXNzICAgICAgICAgICAgICAgICAgIAojICogT3JkZXIgICAgICAgICAgICAgICAgICAgCiMgKiBGYW1pbHkgICAgIAojICogR2VudXMgICAgIAojICogU3BlY2llcyAgCmBgYAoKYGBge3Igc2V0dXB9Cm9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgIHNjaXBlbiA9IDk5OSkKCiMgIyBJbmNyZWFzZSBtbWVtb3J5IHNpemUgdG8gNjQgR2ItLS0tCiMgaW52aXNpYmxlKHV0aWxzOjptZW1vcnkubGltaXQoNjU1MzYpKQojIHN0cihrbml0cjo6b3B0c19jaHVuayRnZXQoKSkKIyAjIE5PVEU6IHRoZSBiZWxvdyBkb2VzIG5vdCB3b3JrIQojIGtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsIAojICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsCiMgICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwKIyAgICAgICAgICAgICAgICAgICAgICAgZXJyb3IgPSBGQUxTRSkKCiMgcmVxdWlyZShrbml0cikKIyByZXF1aXJlKGthYmxlRXh0cmEpCiMgcmVxdWlyZShzaGlueSkKCnJlcXVpcmUocGh5bG9zZXEpCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKHBsb3RseSkKcmVxdWlyZShEVCkKCnNvdXJjZSgic291cmNlL2Z1bmN0aW9uc19tYXkyMDE5LlIiKQpgYGAKCiMgSW50cm9kdWN0aW9uCk5vdmVtYmVyIDIwMTggQmF0Y2g6IE5yZjIgS08gKC0vLSkgTWljZSAgCk1heSAyMDE5IEJhdGNoOiBXaWxkIFR5cGUgTWljZSAgCgojIERhdGEgcHJlcHJvY2Vzc2luZwojIyBSYXcgRGF0YSAKRmFzdFEgZmlsZXMgd2VyZSBkb3dubG9hZGVkIGZyb20gW0RyLiBLdW1hcidzIERyb3BCb3hdKGh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NoL3NtOXRpbm0wZjVyNnkxdi9BQURqR1BSUk5pSU03ek1TZkFORGtRakZhP2RsPTApLiBBIHRvdGFsIG9mIDYwIGZpbGVzICgyIHBlciBzYW1wbGUsIHBhaXItZW5kZWQpIGFuZCAyIG1ldGFkYXRhIGZpbGVzIHdlcmUgZG93bmxvYWRlZC4KCiMjIFNjcmlwdApEYXRhIHByb2Nlc3Npbmcgc2NyaXB0cyAoKioqbnJmMnViaW9tZV9kYWRhMl9ub3YyMDE4X3YxLlJtZCoqKiBhbmQgKioqbnJmMnViaW9tZV9kYWRhMl9tYXkyMDE5X3YxLlJtZCoqKikgd2VyZSBkZXZlbG9wZWQgdXNpbmcgW0RBREEyIFBpcGVsaW5lIFR1dG9yaWFsICgxLjEyKV0oaHR0cHM6Ly9iZW5qam5lYi5naXRodWIuaW8vZGFkYTIvdHV0b3JpYWwuaHRtbCkgd2l0aCB0aXBzIGFuZCB0cmlja3MgZnJvbSB0aGUgW1VuaXZlcnNpdHkgb2YgTWFyeWxhbmQgU2hvb2wgb2YgTWVkaWNpbmUgSW5zdGl0dXRlIGZvciBHZW5vbWUgU2NpZW5jZXMgKElHUyldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvKSBbTWljcm9iaW9tZSBBbmFseXNpcyBXb3Jrc2hvcCAoQXByaWwgOC0xMSwgMjAxOSldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvZWR1Y2F0aW9uL3drc2hwX21ldGFnZW5vbWUucGhwKS4gVGhlIG9yZXN1bHRzIG9mIHRoZSBEQURBMiBzY3JpcHRzICgqKipkYXRhX25vdjIwMTgvcHNfbm92MjAxOC5SRGF0YSoqKiBhbmQgKioqZGF0YV9tYXkyMDE5L3BzX21heTIwMTkuUkRhdGEqKiopIGFyZSBleHBsb3JlZCBpbiB0aGlzIGRvY3VtZW50LgoKIyBNZXRhIGRhdGE6IHNhbXBsZSBkZXNjcmlwdGlvbgpgYGB7ciBkYXRhfQojIExvYWQgZGF0YS0tLS0KIyBDb3VudHMKbG9hZCgiZGF0YV9ub3YyMDE4L3BzX25vdjIwMTguUkRhdGEiKQpwc19ub3YyMDE4IDwtIGNvcHkocHMpCnJtKHBzKQojIFJlbW92ZSAiVW5kZXRlcm1pbmVkIiBzYW1wbGUKcHNfbm92MjAxOCA8LSBzdWJzZXRfc2FtcGxlcyhwc19ub3YyMDE4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOYW1lICE9ICJVbmRldGVybWluZWRfUzAiKQoKbG9hZCgiZGF0YV9tYXkyMDE5L3BzX21heTIwMTkuUkRhdGEiKQoKZ2ModmVyYm9zZSA9IEZBTFNFKQoKIyBUYXhvbm9teSAodXNlIHRoZSBzYW1lIG9uZSBmb3IgYm90aCBiYXRjaGVzISkKbG9hZCgiZGF0YV9tYXkyMDE5L3RheGEuUkRhdGEiKQp0YXhhIDwtIGRhdGEudGFibGUoc2VxMTZzID0gcm93bmFtZXModGF4YSksCiAgICAgICAgICAgICAgICAgICB0YXhhKQoKIyBTYW1wbGVzCm1ldGExOCA8LSBwc19ub3YyMDE4QHNhbV9kYXRhCmRhdGF0YWJsZShtZXRhMTgsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gbnJvdyhtZXRhMTgpKSwKICAgICAgICAgIGNhcHRpb24gPSAiTnJmMiBLTyAoTm92IDE4KSBNZXRhIERhdGEiKQoKbWV0YTE5IDwtIHBzX21heTIwMTlAc2FtX2RhdGEKZGF0YXRhYmxlKG1ldGExOSwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSBucm93KG1ldGExOSkpLAogICAgICAgICAgY2FwdGlvbiA9ICJXVCAoTWF5IDE5KSBNZXRhIERhdGEiKQpgYGAKCiMgT1RVcyBtYXBwZWQgdG8gS2luZ2RvbXMsIGVhY2ggYmF0Y2ggc2VwYXJhdGUKYGBge3IgbWFwcGluZ19raW5nZG9tX2J5X2JhdGNoLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQp0MSA8LSBkYXRhLnRhYmxlKHRhYmxlKHRheF90YWJsZShwc19ub3YyMDE4KVssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLaW5nZG9tIl0sCiAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZSA9IE5VTEwpKQp0MiA8LSBkYXRhLnRhYmxlKHRhYmxlKHRheF90YWJsZShwc19tYXkyMDE5KVssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLaW5nZG9tIl0sCiAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZSA9IE5VTEwpKQp0dDEgPC0gbWVyZ2UodDEsCiAgICAgICAgICAgICB0MiwKICAgICAgICAgICAgIGJ5ID0gIlYxIiwKICAgICAgICAgICAgIGFsbCA9IFRSVUUpCgp0dDEkVjFbaXMubmEodHQxJFYxKV0gPC0gIlVua25vd24iCnR0MSROLnlbaXMubmEodHQxJE4ueSldIDwtIDAKCgp0dDFbLHBjdC54IDo9IE4ueC9zdW0oTi54LCBuYS5ybSA9IFRSVUUpXQp0dDFbLHBjdC55IDo9IE4ueS9zdW0oTi55LCBuYS5ybSA9IFRSVUUpXQp0dDEgPC0gdHQxW29yZGVyKHR0MSROLngsCiAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IFRSVUUpLCBdCgpjb2xuYW1lcyh0dDEpIDwtIGMoIktpbmdkb20iLAogICAgICAgICAgICAgICAgICAgIk51bWJlciBvZiBPVFVzIGluIE5yZjIgS08gTWljZSIsCiAgICAgICAgICAgICAgICAgICAiTnVtYmVyIG9mIE9UVXMgaW4gV1QgTWljZSIsCiAgICAgICAgICAgICAgICAgICAiUGVyY2VudCBvZiBPVFVzIGluIE5yZjIgS08gTWljZSIsCiAgICAgICAgICAgICAgICAgICAiUGVyY2VudCAgb2YgT1RVcyBpbiBXVCBNaWNlIikKCmRhdGF0YWJsZSh0dDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJOdW1iZXIgb2YgT1RVcyBieSBLaW5nZG9tIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHQxKSkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSAyOjMsCiAgICAgICAgICAgICAgICAgY3VycmVuY3kgPSAiIiwKICAgICAgICAgICAgICAgICBtYXJrID0gIiwiLAogICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDApICU+JQogIGZvcm1hdFBlcmNlbnRhZ2UoY29sdW1ucyA9IDQ6NSwKICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDIpCmBgYAoKIyBNZXJnZSB0aGUgMiBkYXRhIHNldHMKYGBge3IgbWVyZ2VfYmF0Y2hlc30KcHNzIDwtIG1lcmdlX3BoeWxvc2VxKHBzX25vdjIwMTgsCiAgICAgICAgICAgICAgICAgICAgICBwc19tYXkyMDE5KQp0bXAgPC0gcHNzQHNhbV9kYXRhCgojIERpZXQKbWV0YSA8LSBkYXRhLnRhYmxlKFNhbXBsZSA9IHJvd25hbWVzKHBzc0BzYW1fZGF0YSksCiAgICAgICAgICAgICAgICAgICBEaWV0ID0gdG1wJERpZXQpCm1ldGEkRGlldCA8LSBnc3ViKHggPSBtZXRhJERpZXQsIAogICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIiBDb250cm9sIiwKICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIikKbWV0YSREaWV0WyFpcy5uYSh0bXAkVFJFQVRNRU5UKV0gPC0gdG1wJFRSRUFUTUVOVFshaXMubmEodG1wJFRSRUFUTUVOVCldCm1ldGEkRGlldCA8LSBnc3ViKHggPSBtZXRhJERpZXQsCiAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkFJTjkzTSIpCm1ldGEkRGlldFtpcy5uYShtZXRhJERpZXQpXSA8LSAiUG9vbGVkIgptZXRhJERpZXQgPC0gZmFjdG9yKG1ldGEkRGlldCwKICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJBSU45M00iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFSVRDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb29sZWQiKSkKCiMgR2Vtb3R5cGUKbWV0YSRHZW5vdHlwZSA8LSAiTnJmMiBLTyIKbWV0YSRHZW5vdHlwZVtpcy5uYSh0bXAkU2V4KV0gPC0gIldpbGQgVHlwZSIKbWV0YSRHZW5vdHlwZSA8LSBmYWN0b3IobWV0YSRHZW5vdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiV2lsZCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTnJmMiBLTyIpKQoKIyBUaW1lCm1ldGEkV2VlayA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih0bXAkV2VlaykpIC0gNAptZXRhJFdlZWtbbWV0YSRHZW5vdHlwZSA9PSAiV2lsZCBUeXBlIl0gPC0gYXMubnVtZXJpYyhnc3ViKHggPSB0bXAkV0VFS1ttZXRhJEdlbm90eXBlID09ICJXaWxkIFR5cGUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIndlZWsgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKSkKbWV0YSRXZWVrIDwtIHBhc3RlKCJXZWVrIiwKICAgICAgICAgICAgICAgICAgIG1ldGEkV2VlaykKCiMgTEFiZWwgY29ycmVjdGlvbiwgYXMgcGVyIFJhbidzIGVtYWlsLCBUdWUsIEFwciAyMSwgMzoyOSBQTSAoNiBkYXlzIGFnbykKbWV0YSRXZWVrW21ldGEkV2VlayA9PSAiV2VlayA1Il0gPC0gIldlZWsgNCIKCiMgbWV0YSRXZWVrIDwtIGZhY3RvcihtZXRhJFdlZWssCiMgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJXZWVrIDAiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgNCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDUiKSkKCm1ldGEkV2VlayA8LSBmYWN0b3IobWV0YSRXZWVrLAogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIldlZWsgMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDQiKSkKCiMgTW91c2UgSUQKbWV0YSRNb3VzZV9OdW0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIodG1wJE1vdXNlTnVtKSkKbWV0YSRNb3VzZV9OdW1bbWV0YSRHZW5vdHlwZSA9PSAiV2lsZCBUeXBlIl0gPC0gYXMubnVtZXJpYyhzdWJzdHIoeCA9IHRtcCRTQU1QTEVfTkFNRVttZXRhJEdlbm90eXBlID09ICJXaWxkIFR5cGUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcCA9IDMpKQoKIyBDYWdlIG51bWJlcgptZXRhJENhZ2UgPC0gYXMuY2hhcmFjdGVyKHRtcCRDYWdlKQptZXRhJENhZ2VbbWV0YSRHZW5vdHlwZSA9PSAiV2lsZCBUeXBlIl0gPC0gc3Vic3RyKHggPSB0bXAkU0FNUExFX05BTUVbbWV0YSRHZW5vdHlwZSA9PSAiV2lsZCBUeXBlIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSAyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gMikKbWV0YSRDYWdlIDwtIGZhY3RvcihtZXRhJENhZ2UpCgptZXRhIDwtIGRhdGEuZnJhbWUobWV0YSkKcm93bmFtZXMobWV0YSkgPC0gbWV0YSRTYW1wbGUKbWV0YQoKIyBFZGl0IG1ldGEgZGF0YQpzYW1wbGVfZGF0YShwc3MpIDwtIG1ldGEKcHNzQHNhbV9kYXRhCmBgYAoKYGBge3IgbWFwcGluZ19raW5nZG9tX2NvbWJpbmVkLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQp0MSA8LSBkYXRhLnRhYmxlKHRhYmxlKHRheF90YWJsZShwc3MpWywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS2luZ2RvbSJdLAogICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGUgPSBOVUxMKSkKdDEkVjFbaXMubmEodDEkVjEpXSA8LSAiVW5rbm93biIKCnQxWywgcGN0IDo9IE4vc3VtKE4pXQpzZXRvcmRlcih0MSwgLU4pCgpjb2xuYW1lcyh0MSkgPC0gYygiS2luZ2RvbSIsCiAgICAgICAgICAgICAgICAgICJOdW1iZXIgb2YgT1RVcyIsCiAgICAgICAgICAgICAgICAgICJQZXJjZW50IG9mIE9UVXMiKQpkYXRhdGFibGUodDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJOdW1iZXIgb2YgT1RVcyBieSBLaW5nZG9tIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHQxKSkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSAyLAogICAgICAgICAgICAgICAgIGN1cnJlbmN5ID0gIiIsCiAgICAgICAgICAgICAgICAgbWFyayA9ICIsIiwKICAgICAgICAgICAgICAgICBkaWdpdHMgPSAwKSAlPiUKICBmb3JtYXRQZXJjZW50YWdlKGNvbHVtbnMgPSAzLAogICAgICAgICAgICAgICAgICAgZGlnaXRzID0gMikKYGBgCgpgYGB7ciBrZWVwX2JhY3RlcmlhfQpkaW0ocHNzQG90dV90YWJsZUAuRGF0YSkKCiMgUmVtb3ZlIE9UVSB1bm1hcHBlZCB0byBCYWN0ZXJpYQpwczAgPC0gc3Vic2V0X3RheGEocHNzLCAKICAgICAgICAgICAgICAgICAgIEtpbmdkb20gPT0gIkJhY3RlcmlhIikKZGltKHBzMEBvdHVfdGFibGVALkRhdGEpCmBgYAoKIyBPVFUgdGFibGUgKGZpcnN0IDEwIHJvd3MpCmBgYHtyIG90dV90YWJsZSwgd2FybmluZz1GQUxTRSxlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0V9Cm90dSA8LSBkYXRhLnRhYmxlKHBzMEB0YXhfdGFibGVALkRhdGEsCiAgICAgICAgICAgICAgICAgIHQocHMwQG90dV90YWJsZUAuRGF0YSkpCgojIFJlbW92ZSBTcGVjaWVzIG1hcHBpbmcnCm90dSRTcGVjaWVzIDwtIE5VTEwKCmRhdGF0YWJsZShoZWFkKG90dSwgMTApLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gMTApKSAlPiUKICBmb3JtYXRDdXJyZW5jeShjb2x1bW5zID0gNzozNiwKICAgICAgICAgICAgICAgICBjdXJyZW5jeSA9ICIiLAogICAgICAgICAgICAgICAgIG1hcmsgPSAiLCIsCiAgICAgICAgICAgICAgICAgZGlnaXRzID0gMCkKYGBgCgojIFRvdGFsIGNvdW50cyBwZXIgc2FtcGxlIChpLmUuIHNlcXVlbmNpbmcgZGVwdGgpCmBgYHtyIHNlcV9kZXB0aF9wbG90bHksIHdhcm5pbmc9RkFMU0UsZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTV9CnQxIDwtIGNvbFN1bXMob3R1WywgNzpuY29sKG90dSldKQp0MSA8LSBkYXRhLnRhYmxlKFNhbXBsZSA9IG5hbWVzKHQxKSwKICAgICAgICAgICAgICAgICBUb3RhbCA9IHQxKQoKc21wbCA8LSBtZXJnZShtZXRhLAogICAgICAgICAgICAgIHQxLAogICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCgpwMSA8LSBnZ3Bsb3Qoc21wbCwKICAgICAgICAgICAgIGFlcyh4ID0gU2FtcGxlLAogICAgICAgICAgICAgICAgIHkgPSBUb3RhbCwKICAgICAgICAgICAgICAgICBmaWxsID1EaWV0LAogICAgICAgICAgICAgICAgIGNvbG91ciA9IFdlZWspKSArCiAgZmFjZXRfd3JhcCh+IEdlbm90eXBlLAogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZSIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX3hfZGlzY3JldGUoIlNhbXBsZSBOYW1lIikgKwogIHNjYWxlX3lfY29udGludW91cygiTnVtYmVyIG9mIFJlYWRzIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIkdyb3VwIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkgCmdncGxvdGx5KHAxKQpgYGAKCmBgYHtyIHNlcV9kZXB0aF9ncmV5c2NhbGUsIGZpZy5oZWlnaHQgPSA2ICwgZmlnLndpZHRoID04fQpwMSA8LSBnZ3Bsb3Qoc21wbCwKICAgICAgICAgICAgIGFlcyh4ID0gU2FtcGxlLAogICAgICAgICAgICAgICAgIHkgPSBUb3RhbCwKICAgICAgICAgICAgICAgICBncm91cCA9RGlldCwKICAgICAgICAgICAgICAgICBmaWxsID0gRGlldCkpICsKICBmYWNldF93cmFwKH4gR2Vub3R5cGUgKyBXZWVrLAogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZSIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwKICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIgb2YgUmVhZHMiKSArCiAgc2NhbGVfZmlsbF9ncmV5KCJUcmVhdG1lbnQiLCAKICAgICAgICAgICAgICAgICAgc3RhcnQgPSAwLjEsIAogICAgICAgICAgICAgICAgICBlbmQgPSAxLAogICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJyZWQiLAogICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIyBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSksCiAgICAgICAgIyBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2VxX2RlcHRoX25vdjIwMThfbWF5MjAxOS50aWZmIiwKICAgICBoZWlnaHQgPTYsCiAgICAgd2lkdGggPSA4LAogICAgIHVuaXRzID0gImluIiwKICAgICByZXMgPSA2MDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpwcmludChwMSkKZ3JhcGhpY3Mub2ZmKCkKCnByaW50KHAxKQpgYGAKCgpgYGB7ciBwaHlsdW1fbWFwcGluZ30KdDIgPC0gZGF0YS50YWJsZSh0YWJsZSh0YXhfdGFibGUocHMwKVssICJQaHlsdW0iXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGUgPSBOVUxMKSkKdDIkVjFbaXMubmEodDIkVjEpXSA8LSAiVW5rbm93biIKc2V0b3JkZXIodDIsIC1OKQp0MlssIHBjdCA6PSBOL3N1bShOKV0Kc2V0b3JkZXIodDIsIC1OKQoKY29sbmFtZXModDIpIDwtIGMoIlBoeWx1bSIsCiAgICAgICAgICAgICAgICAgICJOdW1iZXIgb2YgT1RVcyIsCiAgICAgICAgICAgICAgICAgICJQZXJjZW50IG9mIE9UVXMiKQoKZGF0YXRhYmxlKHQyLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiTnVtYmVyIG9mIEJhY3RlcmlhbCBPVFVzIGJ5IFBoeWx1bSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyh0MikpKSAlPiUKICBmb3JtYXRDdXJyZW5jeShjb2x1bW5zID0gMiwKICAgICAgICAgICAgICAgICBjdXJyZW5jeSA9ICIiLAogICAgICAgICAgICAgICAgIG1hcmsgPSAiLCIsCiAgICAgICAgICAgICAgICAgZGlnaXRzID0gMCkgJT4lCiAgZm9ybWF0UGVyY2VudGFnZShjb2x1bW5zID0gMywKICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDIpCgpwczEgPC0gc3Vic2V0X3RheGEocHMwLCAKICAgICAgICAgICAgICAgICAgICFpcy5uYShQaHlsdW0pKQpkaW0ocHMxQG90dV90YWJsZUAuRGF0YSkKYGBgCgojIFJlbW92ZSBQaHlsdW0KUmVtb3ZlOiAgCjEuIFVubWFwcGVkIE9UVXMgKCJVbmtub3duIikuICAgIAoyLiBDeWFub2JhY3RlcmlhOiBhZXJvYmljLCBwaG90b3N5bnRoZXNpemluZyAgYmFjdGVyaWEgdGhhdCBwcm9iYWJseSBnb3QgaW50byB0aGUgc2FtcGxlIHRocm91Z2ggZm9vZC4gIApOT1RFOiBbQ2hsb3JvZmxleGkgbWlnaHQgYmUgb2suXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0MTkyODQwLykgIAogIApgYGB7ciByZW1vdmVfcGh5bHVtc30KcHMwIDwtIHN1YnNldF90YXhhKHBzMCwKICAgICAgICAgICAgICAgICAgICghKFBoeWx1bSAlaW4lIGMoIlVua25vd24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDeWFub2JhY3RlcmlhIikpKSkKYGBgCgojIFJpY2huZXNzIChBbHBoYSBkaXZlcnNpdHkpClNoYW5ub24gaW5kZXggKGFrYSBTaGFubm9uIGVudGhyb3BoeSkgaXMgY2FsY3VsYXRlZCBhczogIApIJyA9IC1zdW0oMSB0byBSKXAoaSlsbihwKGkpKSAKV2hlbiB0aGVyZSBpcyBleGFjdGx5IDEgdHlwZSBvZiBkYXRhIChlLmcuIGEgc2luZ2xlIHNwZWNpZXMgaW4gdGhlIHNhbXBsZSksIEgnPTAuIFRoZSBvcHBvc2l0ZSBzY2VuYXJpbyBpcyB3aGVuIHRoZXJlIGFyZSBSPjEgc3BlY2llcyBwcmVzZW50IGluIHRoZSBzYW1wbGUgaW4gdGhlIGV4YWN0IHNhbWUgYW1vdW50cyBhbmQgSCc9bG4oUikuICAKICAKU2hhbm5vbidzIGRpdmVyc2l0eSBpbmRleCB3YXMgY2FsY3VsYXRlZCBmb3IgZWFjaCBzYW1wbGUgYW5kIHBsb3RlZCBvdmVyIHRpbWUuCgpgYGB7ciBzaGFubm9uX3ZzX2RlcHRoLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNn0Kc2hhbm5vbi5uZHggPC0gZXN0aW1hdGVfcmljaG5lc3MocHMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlcyA9ICJTaGFubm9uIikKCnNoYW5ub24ubmR4IDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoc2hhbm5vbi5uZHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNoYW5ub24ubmR4KQoKc21wbCA8LSBtZXJnZShzbXBsLAogICAgICAgICAgICAgIHNoYW5ub24ubmR4LAogICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCgpwMSA8LSBnZ3Bsb3Qoc21wbCwKICAgICAgICAgICAgIGFlcyh4ID0gVG90YWwsCiAgICAgICAgICAgICAgICAgeSA9IFNoYW5ub24sCiAgICAgICAgICAgICAgICAgZmlsbCA9IEdlbm90eXBlLAogICAgICAgICAgICAgICAgIHNoYXBlID0gV2VlaykpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKGJyZWFrcyA9IHVuaXF1ZShzbXBsJFdlZWspLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAyMToyNCkKCnRpZmYoZmlsZW5hbWUgPSAidG1wL3NoYW5ub25fdnNfZGVwdGhfbm92MThfbWF5MTkudGlmZiIsCiAgICAgaGVpZ2h0ID0gNSwKICAgICB3aWR0aCA9IDYsCiAgICAgdW5pdHMgPSAiaW4iLAogICAgIHJlcyA9IDYwMCwKICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpCnByaW50KHAxKQpncmFwaGljcy5vZmYoKQoKZ2dwbG90bHkocDEpCmBgYAoKRXZlbiB0aG91Z2ggKioqZXN0aW1hdGVfcmljaG5lc3MqKiogZnVuY3Rpb24gZG9lcyBub3QgYWRqdXN0IGZvciB0aGUgc2VxdWVuY2luZyBkZXB0aCwgdGhlcmUgaXMgbm8gY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgaW5kZXggYW5kIHRoZSBzYW1wbGUncyBzZXF1ZWNpbmcgZGVwdGguIFByb2NlZWQgd2l0aCB0aGUgY29tcGFyaXNvbi4KCiMgU2hhbm5vbiBpZGV4IG92ZXIgdGltZQpgYGB7ciByaWNobmVzcywgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDh9CnAxIDwtIHBsb3RfcmljaG5lc3MocHMwLAogICAgICAgICAgICAgICAgICAgIHggPSAiV2VlayIsIAogICAgICAgICAgICAgICAgICAgIG1lYXN1cmVzID0gIlNoYW5ub24iKSArCiAgZmFjZXRfd3JhcCh+IEdlbm90eXBlLAogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV94IikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBwYXN0ZTAoRGlldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb3VzZV9OdW0pKSwKICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IERpZXQpLAogICAgICAgICAgICAgc2hhcGUgPSAyMSwKICAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMSkpCgpnZ3Bsb3RseShwID0gcDEsCiAgICAgICAgIHRvb2x0aXAgPSBjKCJNb3VzZV9OdW0iLAogICAgICAgICAgICAgICAgICAgICAidmFsdWUiKSkKCnAxIDwtIHAxICsgCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2hhbm5vbl9ub3YxOF9tYXkxOS50aWZmIiwKICAgICBoZWlnaHQgPSA1LAogICAgIHdpZHRoID0gOCwKICAgICB1bml0cyA9ICJpbiIsCiAgICAgcmVzID0gNjAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCmBgYAoKVGhlIHBsb3QgYWJvdmUgc3VnZ2VzdHMgdGhhdCB0aGUgbGFyZ2VzdCBkaWZmZXJlbmNlcyBpbiBhbHBoYSBkaXZlcnNpdHkgKGFzIG1lYXN1cmVkIGJ5IFNoYW5ub24ncyBpbmRleCkgYXJlIGluIGdlbm90eXBlLiBUSGlzIHdhcyBhbHNvIGNvbmZpcm1lZCBpbiB0aGUgM3JkIHN0dWR5IChTZXB0ZW1iZXIgMjAxOSBiYXRjaCkKCiMgQXZlcmFnZSBTaGFubm9uIEluZGV4CmBgYHtyIGF2Z19zaGFubm9uX3Bsb3QsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA2fQojIEF2ZXJhZ2Ugc2hhbm5vbiBpbmRleCBieSB0cmVhdG1lbnQgZ3JvdXAKdG1wIDwtIGRhdGEudGFibGUoY29weShzbXBsKSkKCnRtcFssIG11IDo9IG1lYW4oU2hhbm5vbiksCiAgICBieSA9IGxpc3QoRGlldCwKICAgICAgICAgICAgICBHZW5vdHlwZSwKICAgICAgICAgICAgICBXZWVrKV0KdG1wWywgc2VtIDo9IHNkKFNoYW5ub24pL3NxcnQoLk4pLAogICAgYnkgPSBsaXN0KERpZXQsCiAgICAgICAgICAgICAgR2Vub3R5cGUsCiAgICAgICAgICAgICAgV2VlayldCnRtcCA8LSB1bmlxdWUodG1wWywgYygiRGlldCIsCiAgICAgICAgICAgICAgICAgICAgICAiR2Vub3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgIldlZWsiLAogICAgICAgICAgICAgICAgICAgICAgIm11IiwKICAgICAgICAgICAgICAgICAgICAgICJzZW0iKV0pCgpwMSA8LSBnZ3Bsb3QodG1wLAogICAgICAgICAgICAgYWVzKHggPSBXZWVrLAogICAgICAgICAgICAgICAgIHkgPSBtdSwKICAgICAgICAgICAgICAgICB5bWluID0gbXUgLSBzZW0sCiAgICAgICAgICAgICAgICAgeW1heCA9IG11ICsgc2VtLAogICAgICAgICAgICAgICAgIGZpbGwgPSBEaWV0LAogICAgICAgICAgICAgICAgIGdyb3VwID0gRGlldCkpICsKICBmYWNldF93cmFwKH4gR2Vub3R5cGUsCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3giKSArCiAgZ2VvbV9lcnJvcmJhcihwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMyksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuNCkgKwogIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMykpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLAogICAgICAgICAgICAgc2hhcGUgPSAyMSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC4zKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIlNoYW5ub24gSW5kZXgiKSArCiAgc2NhbGVfZmlsbF9ncmV5KCJUcmVhdG1lbnQiLCAKICAgICAgICAgICAgICAgICAgc3RhcnQgPSAwLCAKICAgICAgICAgICAgICAgICAgZW5kID0gMSwKICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICMgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIyBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2F2Z19zaGFubm9uX25vdjE4X21heTE5LnRpZmYiLAogICAgIGhlaWdodCA9IDQsCiAgICAgd2lkdGggPSA2LAogICAgIHVuaXRzID0gImluIiwKICAgICByZXMgPSA2MDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpwcmludChwMSkKZ3JhcGhpY3Mub2ZmKCkKCnByaW50KHAxKQpgYGAKCk5PVEU6IGNhbm5vdCB0ZXN0IGRpZXQgZWZmZWN0IGJlY2F1c2Ugb2YgdW5hc3NpZ2VuZCBwb29sZWQgc2FtcGxlcyBpbiB0aGUgS08gbWljZS4gRm9yIHRoZSBzYW1lIHJlYXNvbiwgY2Fubm90IHVzZSBtaXhlZCBlZmZlY3RzIG1vZGVsIG9uIHRoZSB3aG9sZSBkYXRhIHNldC4gQXQgYmVzdCwgdGVzdGluZyBnZW5vdHlwZSBhbmQgdGltZSB0cmVuZCBieSBhc3N1bWluZyBXZWVrIDQgaW4gV1QgPSBXZWVrIDUgaW4gS08uCmBgYHtyIHRlc3RfcmljaG5lc3N9CnNtcGwkVGltZXBvaW50IDwtIGFzLm51bWVyaWMoc21wbCRXZWVrKQpzbXBsJFRpbWVwb2ludFtzbXBsJFRpbWVwb2ludCA9PSA0XSA8LSAzCgptMSA8LSBsbShTaGFubm9uIH4gVGltZXBvaW50Kkdlbm90eXBlLAogICAgICAgICBkYXRhID0gc21wbCkKc3VtbWFyeShtMSkKYGBgCgpObyBzaWduaWZpY2FudCB0aW1lIHRyZW5kOyBzaWduaWZpY2FudGx5IGhpZ2hlciBhbHBoYSBkaXZlcnNpdHkgaW4gdGhlIE5yZjIgS08gbWljZS4gVGhpcyBpcyBwb3NzaWJseSBhIGJhdGNoIGVmZmVjdCBidXQgd2Ugb2JzZXJ2ZWQgc2FtZSB0cmVuZCBpbiBTdHVkeSAzIChDcmFiYmVyeSBhbmQgUEVJVEMgd2l0aCBib3RoIGdlbm90eXBlcyBpbiB0aGUgc2FtZSBzdHVkeSkuCgojIEJhY3RlcmlvdGlkZXMgdnMuIEZpcm1pY3V0ZXMKYGBge3IgYmFjdF92c19maXJtLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOCwgd2FybmluZyA9IEZBTFNFfQpjb3VudHNfcCA8LSBjb3VudHNfYnlfdGF4X3JhbmsoZHQxID0gb3R1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncl9ieSA9ICJQaHlsdW0iKQoKZmIgPC0gdChjb3VudHNfcFtQaHlsdW0gJWluJSBjKCJCYWN0ZXJvaWRldGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGaXJtaWN1dGVzIiksIC0xXSkKZmIgPC0gZGF0YS50YWJsZShTYW1wbGUgPSByb3duYW1lcyhmYiksCiAgICAgICAgICAgICAgICAgQmFjdGVyb2lkZXRlcyA9IGZiWywgMV0sCiAgICAgICAgICAgICAgICAgRmlybWljdXRlcyA9IGZiWywgMl0pCmZiIDwtIGRhdGEudGFibGUobWVyZ2UobWV0YSwKICAgICAgICAgICAgZmIsCiAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpKQoKbGltcyA8LSBsb2cyKHJhbmdlKGMoZmIkQmFjdGVyb2lkZXRlcywKICAgICAgICAgICAgICAgICAgICAgZmIkRmlybWljdXRlcykpKQoKcDEgPC0gZ2dwbG90KGZiLAogICAgICAgICAgICAgYWVzKHggPSBsb2cyKEJhY3Rlcm9pZGV0ZXMpLAogICAgICAgICAgICAgICAgIHkgPSBsb2cyKEZpcm1pY3V0ZXMpLAogICAgICAgICAgICAgICAgIGZpbGwgPSBHZW5vdHlwZSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMSkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwKICAgICAgICAgICAgICBpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gbGltcykgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBsaW1zKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKICAKCnAyIDwtIGdncGxvdChmYiwKICAgICAgICAgICAgIGFlcyh4ID0gbG9nMihCYWN0ZXJvaWRldGVzKSwKICAgICAgICAgICAgICAgICB5ID0gbG9nMihGaXJtaWN1dGVzKSwKICAgICAgICAgICAgICAgICBmaWxsID0gV2VlaykpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMSkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwKICAgICAgICAgICAgICBpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gbGltcykgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBsaW1zKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCnAzIDwtIGdncGxvdChmYiwKICAgICAgICAgICAgIGFlcyh4ID0gbG9nMihCYWN0ZXJvaWRldGVzKSwKICAgICAgICAgICAgICAgICB5ID0gbG9nMihGaXJtaWN1dGVzKSwKICAgICAgICAgICAgICAgICBmaWxsID0gRGlldCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMSkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwKICAgICAgICAgICAgICBpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gbGltcykgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBsaW1zKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCnA0IDwtIGdncGxvdChmYiwKICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywKICAgICAgICAgICAgICAgICB5ID0gQmFjdGVyb2lkZXRlcy9GaXJtaWN1dGVzLAogICAgICAgICAgICAgICAgIGZpbGwgPSBEaWV0LAogICAgICAgICAgICAgICAgIGdyb3VwID0gcGFzdGUwKERpZXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDYWdlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW91c2VfTnVtKSkpICsKICBmYWNldF9ncmlkKH4gR2Vub3R5cGUsCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3giKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjMpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMiwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNoYXBlID0gMjEsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMykpICArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgIyBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSwKICAgICAgICAjIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgp0aWZmKGZpbGVuYW1lID0gInRtcC9iYWN0X3ZzX2Zpcm1fbm92MThfbWF5MTkudGlmZiIsCiAgICAgaGVpZ2h0ID0gNiwKICAgICB3aWR0aCA9OCwKICAgICB1bml0cyA9ICJpbiIsCiAgICAgcmVzID0gNjAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDQpCmdyYXBoaWNzLm9mZigpCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMSwgcDIsIHAzLCBwNCkKYGBgCgpgYGB7ciBhdmdfYmFjdF9maXJtLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNn0KZmJbLCBCX0YgOj0gQmFjdGVyb2lkZXRlcy9GaXJtaWN1dGVzXQpmYlssIGxvZzJfQl9GIDo9IGxvZzIoQl9GKV0KCm0xIDwtIGxtKGxvZzJfQl9GIH4gMCArIFdlZWsqRGlldCwKICAgICAgICAgZGF0YSA9IGRyb3BsZXZlbHMoZmJbR2Vub3R5cGUgPT0gIldpbGQgVHlwZSIsIF0pKQpzMSA8LSBzdW1tYXJ5KG0xKQpjaTEgPC0gY29uZmludChtMSkKdDEgPC0gZGF0YS50YWJsZShUZXJtID0gcm93bmFtZXMoczEkY29lZmZpY2llbnRzKSwKICAgICAgICAgICAgICAgICBSYXRpbyA9IHJvdW5kKDJeczEkY29lZmZpY2llbnRzWywgMV0sIDMpLAogICAgICAgICAgICAgICAgIGA5NSUgQy5JLkwuTC5gID0gcm91bmQoMl5jaTFbLCAxXSwgMyksCiAgICAgICAgICAgICAgICAgYDk1JSBDLkkuVS5MLmAgPSByb3VuZCgyXmNpMVssIDJdLCAzKSwKICAgICAgICAgICAgICAgICBgcC1WYWx1ZWAgPSByb3VuZChzMSRjb2VmZmljaWVudHNbLCA0XSwgMyksCiAgICAgICAgICAgICAgICAgU2lnbiA9ICIiKQp0MSRTaWduW3QxJGBwLVZhbHVlYCA8IDAuMDVdIDwtICIqIgp0MSRTaWduW3QxJGBwLVZhbHVlYCA8IDAuMDFdIDwtICIqKiIKdDEkYHAtVmFsdWVgW3QxJGBwLVZhbHVlYCA8IDAuMDAxXSA8LSAiPDAuMDAxIgpkYXRhdGFibGUodDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIGNhcHRpb24gPSAiV2lsZCBUeXBlIikKCm0yIDwtIGxtKGxvZzJfQl9GIH4gMCArIFdlZWsqRGlldCwKICAgICAgICAgZGF0YSA9IGRyb3BsZXZlbHMoZmJbR2Vub3R5cGUgPT0gIk5yZjIgS08iLCBdKSkKczIgPC0gc3VtbWFyeShtMikKY2kyIDwtIGNvbmZpbnQobTIpCmNpMiA8LSBjaTJbIWlzLm5hKGNpMlssIDFdKSxdCnQyIDwtIGRhdGEudGFibGUoVGVybSA9IHJvd25hbWVzKHMyJGNvZWZmaWNpZW50cyksCiAgICAgICAgICAgICAgICAgUmF0aW8gPSByb3VuZCgyXnMyJGNvZWZmaWNpZW50c1ssIDFdLCAzKSwKICAgICAgICAgICAgICAgICBgOTUlIEMuSS5MLkwuYCA9IHJvdW5kKDJeY2kyWywgMV0sIDMpLAogICAgICAgICAgICAgICAgIGA5NSUgQy5JLlUuTC5gID0gcm91bmQoMl5jaTJbLCAyXSwgMyksCiAgICAgICAgICAgICAgICAgYHAtVmFsdWVgID0gcm91bmQoczIkY29lZmZpY2llbnRzWywgNF0sIDMpLAogICAgICAgICAgICAgICAgIFNpZ24gPSAiIikKdDIkU2lnblt0MiRgcC1WYWx1ZWAgPCAwLjA1XSA8LSAiKiIKdDIkU2lnblt0MiRgcC1WYWx1ZWAgPCAwLjAxXSA8LSAiKioiCnQyJGBwLVZhbHVlYFt0MiRgcC1WYWx1ZWAgPCAwLjAwMV0gPC0gIjwwLjAwMSIKZGF0YXRhYmxlKHQyLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBjYXB0aW9uID0gIk5yZjIgS08iKQoKZmJbLCBtdSA6PSBtZWFuKEJhY3Rlcm9pZGV0ZXMvRmlybWljdXRlcyksCiAgIGJ5ID0gYygiRGlldCIsCiAgICAgICAgICAiR2Vub3R5cGUiLAogICAgICAgICAgIldlZWsiKV0KZmJbLCBzZW0gOj0gc2QoQmFjdGVyb2lkZXRlcy9GaXJtaWN1dGVzKS9zcXJ0KC5OKSwKICAgYnkgPSBjKCJEaWV0IiwKICAgICAgICAgICJHZW5vdHlwZSIsCiAgICAgICAgICAiV2VlayIpXQoKbXVmYiA8LSB1bmlxdWUoZmJbLCBjKCJEaWV0IiwKICAgICAgICAgICAgICAgICAgICAgICJHZW5vdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAiV2VlayIsCiAgICAgICAgICAgICAgICAgICAgICAibXUiLAogICAgICAgICAgICAgICAgICAgICAgInNlbSIpXSkKCnA1IDwtIGdncGxvdChtdWZiLAogICAgICAgICAgICAgYWVzKHggPSBXZWVrLAogICAgICAgICAgICAgICAgIHkgPSBtdSwKICAgICAgICAgICAgICAgICB5bWluID0gbXUgLSBzZW0sCiAgICAgICAgICAgICAgICAgeW1heCA9IG11ICsgc2VtLAogICAgICAgICAgICAgICAgIGZpbGwgPSBEaWV0LAogICAgICAgICAgICAgICAgIGdyb3VwID0gRGlldCkpICsKICBmYWNldF93cmFwKH4gR2Vub3R5cGUsCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3giKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2Vycm9yYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC4zKSwKICAgICAgICAgICAgICAgIHdpZHRoID0gMC40KSArCiAgZ2VvbV9saW5lKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC4zKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsCiAgICAgICAgICAgICBzaGFwZSA9IDIxLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjMpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKwogIHNjYWxlX3lfY29udGludW91cygiQmFjdGVyb2lkZXRlcy9GaXJtaWN1dGVzIikgKwogIHNjYWxlX2ZpbGxfZ3JleSgiVHJlYXRtZW50IiwgCiAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMCwgCiAgICAgICAgICAgICAgICAgIGVuZCA9IDEsCiAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gInJlZCIsCiAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAjIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICMgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLAogICAgICAgICMgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2F2Z19iYWN0X2Zpcm1fbm92MThfbWF5MTkudGlmZiIsCiAgICAgaGVpZ2h0ID0gNCwKICAgICB3aWR0aCA9IDYsCiAgICAgdW5pdHMgPSAiaW4iLAogICAgIHJlcyA9IDYwMCwKICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpCnByaW50KHA1KQpncmFwaGljcy5vZmYoKQoKcHJpbnQocDUpCgptdWZiWywgZXN0IDo9IHBhc3RlMChyb3VuZChtdSwgMiksCiAgICAgICAgICAgICAgICAgICAgICIoIiwKICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2VtLCAyKSwKICAgICAgICAgICAgICAgICAgICAgIikiKV0KCnQxIDwtIGRjYXN0LmRhdGEudGFibGUobXVmYiwKICAgICAgICAgICAgICAgICAgICAgICBHZW5vdHlwZSArIERpZXQgfiBXZWVrLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLnZhciA9ICJlc3QiKQpkYXRhdGFibGUodDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIGNhcHRpb24gPSAiQXZlcmFnZSBSYXRpbyBhbmQgU0Qgb2YgQmFjdGVyb2lkZXRlcyBhbmQgRmlybWljdXRlcyIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHQxKSkpCmBgYAoKIyBBbHRlcm5hdGl2ZSBGaWcgNwpgYGB7ciBmaWc3X2FsdH0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvZmlnN19hbHRfYmFjdF92c19maXJtX25vdjE4X21heTE5LnRpZmYiLAogICAgIGhlaWdodCA9IDYsCiAgICAgd2lkdGggPTgsCiAgICAgdW5pdHMgPSAiaW4iLAogICAgIHJlcyA9IDYwMCwKICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA1KQpncmFwaGljcy5vZmYoKQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDUpCmBgYAoKCiMgVXBkYXRlIE9UVSB0YWJsZTogZXhjdWRlZCB1bmtub3duIHBoeWx1bSBhbmQgQ3lhbm9iYWN0ZXJpYQpgYGB7ciB1cGRhdGVfb3R1fQpvdHUgPC0gZGF0YS50YWJsZShwczBAdGF4X3RhYmxlQC5EYXRhLAogICAgICAgICAgICAgICAgICB0KHBzMEBvdHVfdGFibGVALkRhdGEpKQoKIyBSZW1vdmUgU3BlY2llcyBtYXBwaW5nJwpvdHUkU3BlY2llcyA8LSBOVUxMCmRpbShvdHUpCmBgYAoKIyAxLiBQaHlsdW0KIyMgQ291bnRzIGF0IFBoeWx1bSBsZXZlbApgYGB7ciBjb3VudHNfcCwgd2FybmluZz1GQUxTRSxlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmNvdW50c19wIDwtIGNvdW50c19ieV90YXhfcmFuayhkdDEgPSBvdHUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyX2J5ID0gIlBoeWx1bSIpCnNldG9yZGVyKGNvdW50c19wLCAtYDRBYCkKZGF0YXRhYmxlKGNvdW50c19wLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyhjb3VudHNfcCkpKSAlPiUKICBmb3JtYXRDdXJyZW5jeShjb2x1bW5zID0gMjpuY29sKGNvdW50c19wKSwKICAgICAgICAgICAgICAgICBjdXJyZW5jeSA9ICIiLAogICAgICAgICAgICAgICAgIG1hcmsgPSAiLCIsCiAgICAgICAgICAgICAgICAgZGlnaXRzID0gMCkKYGBgCgojIyBSZWxhdGl2ZSBhYnVuZGFuY2UgKCUpIGF0IFBoeWx1bSBsZXZlbApgYGB7ciByYV9wLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KcmFfcCA8LSByYV9ieV90YXhfcmFuayhjb3VudHMgPSBjb3VudHNfcCwKICAgICAgICAgICAgICAgICAgICAgICBwY3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBkaWdpdCA9IDQpCgpkYXRhdGFibGUocmFfcCwKICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICBjYXB0aW9uID0gIlRheG9ub21pYyAgY291bnQgdGFibGUiLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNlYXJjaCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IG5yb3cocmFfcCkpKSAlPiUKICBmb3JtYXRQZXJjZW50YWdlKGNvbHVtbnMgPSAyOm5jb2woY291bnRzX3ApLAogICAgICAgICAgICAgICAgICAgZGlnaXRzID0gMikKYGBgCgojIyBQQ0EgYXQgUGh5bHVtIGxldmVsCmBgYHtyIHBjYV9wX3AwLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNn0KZHRfcGNhIDwtIHQocmFfcFssIDI6bmNvbChyYV9wKV0pCmNvbG5hbWVzKGR0X3BjYSkgPC0gcmFfcCRQaHlsdW0KCmR0X3BjYV9wIDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoZHRfcGNhKSwKICAgICAgICAgICAgICAgICAgICAgICBkdF9wY2EpCmR0X3BjYV9wIDwtIG1lcmdlKHNtcGwsCiAgICAgICAgICAgICAgICAgIGR0X3BjYV9wLAogICAgICAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQoKIyBLZWVwIG9ubHkgdGhlIHBoeWx1bSB3aXRoIG5vbi16ZXJvIGNvdW50cwp0bXAgPC0gZHRfcGNhX3BbLCAxMDpuY29sKGR0X3BjYV9wKV0Ka2VlcF9wIDwtIGNvbG5hbWVzKHRtcClbY29sU3Vtcyh0bXApID4gMF0KZHRfcGNhIDwtIGR0X3BjYVssIGtlZXBfcF0KCiMgbTEgPC0gcHJjb21wKGR0X3BjYSwKIyAgICAgICAgICAgICAgY2VudGVyID0gVFJVRSwKIyAgICAgICAgICAgICAgc2NhbGUuID0gVFJVRSkKCiMgbTEgPC0gcHJjb21wKGR0X3BjYSwKIyAgICAgICAgICAgICAgY2VudGVyID0gRkFMU0UsCiMgICAgICAgICAgICAgIHNjYWxlLiA9IEZBTFNFKQoKbTEgPC0gcHJjb21wKGR0X3BjYSwKICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsCiAgICAgICAgICAgICBzY2FsZS4gPSBGQUxTRSkKCnN1bW1hcnkobTEpCgojIFNlbGVjdCBQQy1zIHRvIHBsaW90IChQQzEgJiBQQzIpCmNob2ljZXMgPC0gMToyCgojIEFkZCBtZXRhIGRhdGEKZHQuc2NyIDwtIGRhdGEudGFibGUobTEkeFssIGNob2ljZXNdKQpkdC5zY3IkU2FtcGxlIDwtIHJvd25hbWVzKG0xJHgpCgpkdC5zY3IgPC0gbWVyZ2Uoc21wbCwKICAgICAgICAgICAgICAgIGR0LnNjciwKICAgICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCmR0LnNjcgoKIyBMb2FkaW5ncywgaS5lLiBhcnJvd3MgKGRmLnYpCmR0LnJvdCA8LSBhcy5kYXRhLmZyYW1lKG0xJHJvdGF0aW9uWywgY2hvaWNlc10pCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkKZHQucm90IDwtIGRhdGEudGFibGUoZHQucm90KQpkdC5yb3QKCmR0LmxvYWQgPC0gbWVsdC5kYXRhLnRhYmxlKGR0LnJvdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9ICJmZWF0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMToyLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gInBjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJsb2FkaW5nIikKZHQubG9hZCRmZWF0IDwtIGZhY3RvcihkdC5sb2FkJGZlYXQsCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGR0LmxvYWQkZmVhdCkpCiMgUGxvdCBsb2FkaW5ncwpwMCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LmxvYWQsCiAgICAgICAgICAgICBhZXMoeCA9IGZlYXQsCiAgICAgICAgICAgICAgICAgeSA9IGxvYWRpbmcpKSArCiAgZmFjZXRfd3JhcCh+IHBjLAogICAgICAgICAgICAgbnJvdyA9IDIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBDIExvYWRpbmdzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkKcDAKCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjLjEuMl9sb2FkaW5nc19waHlsdW0udGlmZiIsCiAgICAgaGVpZ2h0ID0gNSwKICAgICB3aWR0aCA9IDYsCiAgICAgdW5pdHMgPSAnaW4nLAogICAgIHJlcyA9IDMwMCwKICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpCnByaW50KHAwKQpncmFwaGljcy5vZmYoKQoKcHJpbnQocDApCmBgYAoKYGBge3IgcGNhX2F4ZXNwfQojIEF4aXMgbGFiZWxzCnUuYXhpcy5sYWJzIDwtIHBhc3RlKGNvbG5hbWVzKGR0LnJvdClbMToyXSwgCiAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCptMSRzZGV2W2Nob2ljZXNdXjIvc3VtKG0xJHNkZXZeMikpKQp1LmF4aXMubGFicwpgYGAKCmBgYHtyIGJpcGxvdF9nZW5fcCwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CmNudHIgPC0gZGF0YS50YWJsZShhZ2dyZWdhdGUoeCA9IGR0LnNjciRQQzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KGR0LnNjciRHZW5vdHlwZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gIm1lYW4iKSwKICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZSh4ID0gZHQuc2NyJFBDMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoZHQuc2NyJEdlbm90eXBlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSAibWVhbiIpJHgpCmNvbG5hbWVzKGNudHIpIDwtIGMoIkdlbm90eXBlIiwKICAgICAgICAgICAgICAgICAgICAiUEMxIiwKICAgICAgICAgICAgICAgICAgICAiUEMyIikKCiMgQmFzZWQgb24gRmlndXJlIHAwLCBrZWVwIG9ubHkgYSBmZXcgdmFyaWFibGVzIHdpdGggaGlnaCBsb2FkaW5ncyBpbiBQQzEgYW5kIFBDMi0tLS0KZHQucm90WywgcmF0aW5nOj0gKFBDMSleMiArIChQQzIpXjJdCnNldG9yZGVyKGR0LnJvdCwgLXJhdGluZykKCiMgU2VsZWN0IHRvcCA1CmR0LnJvdCA8LSBkdC5yb3RbMTo1LCBdCgojIHZhci5rZWVwLm5keCA8LSB3aGljaChkdC5yb3QkZmVhdCAlaW4lIGMoLi4uKSkKIyBPciBzZWxlY3QgYWxsCiMgdmFyLmtlZXAubmR4IDwtIDM6bmNvbChkdDEpCiMgVXNlIGR0LnJvdFt2YXIua2VlcC5uZHgsXSBhbmQgZHQucm90JGZlYXRbdmFyLmtlZXAubmR4XQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnJvdCwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIpKSArCiAgIyBjb29yZF9lcXVhbCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdC5zY3IsCiAgICAgICAgICAgICBhZXMoZmlsbCA9IEdlbm90eXBlLAogICAgICAgICAgICAgICAgIHNoYXBlID0gZmFjdG9yKFRpbWVwb2ludCkpLAogICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsCiAgICAgICAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgICAgICAgIHhlbmQgPSAwLjIqUEMxLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IDAuMipQQzIpLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMS8yLCAncGljYXMnKSksCiAgICAgICAgICAgICAgICMgc2l6ZSA9IDEsIAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKHggPSAwLjIyKlBDMSwKICAgICAgICAgICAgICAgIHkgPSAwLjIyKlBDMiwKICAgICAgICAgICAgICAgIGxhYmVsID0gZHQucm90JGZlYXQpLAogICAgICAgICAgICAjIHNpemUgPSA1LAogICAgICAgICAgICBoanVzdCA9IDAuNSkgKwogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKwogIHNjYWxlX3lfY29udGludW91cyh1LmF4aXMubGFic1syXSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiR3JvdXAiLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIldpbGQgVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTnJmMiBLTyIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKGJyZWFrcyA9IDE6MywKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gMjE6MjMpICsKICBnZW9tX2xhYmVsKGRhdGEgPSBjbnRyLAogICAgICAgICAgICAgYWVzKHggPSBQQzEsCiAgICAgICAgICAgICAgICAgeSA9IFBDMiwKICAgICAgICAgICAgICAgICBsYWJlbCA9IEdlbm90eXBlLAogICAgICAgICAgICAgICAgIGNvbG91ciA9IEdlbm90eXBlKSwKICAgICAgICAgICAgIGFscGhhID0gMC41LAogICAgICAgICAgICAgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoZ3VpZGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygiV2lsZCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTnJmMiBLTyIpLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIikpICsKICBnZ3RpdGxlKCIiKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgp0aWZmKGZpbGVuYW1lID0gInRtcC9waHlsdW1fYmlwbG90X2dycC50aWZmIiwKICAgICBoZWlnaHQgPSA3LAogICAgIHdpZHRoID0gNywKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCgpnZ3Bsb3RseShwMSkKCiMgR2VuZXJpYyBiaXBsb3QKYmlwbG90KG0xKQpgYGAKCiMgMi4gQ2xhc3MKIyMgQ291bnRzIGF0IENsYXNzIGxldmVsCmBgYHtyIGNvdW50c19jLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KY291bnRzX2MgPC0gY291bnRzX2J5X3RheF9yYW5rKGR0MSA9IG90dSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JfYnkgPSAiQ2xhc3MiKQpzZXRvcmRlcihjb3VudHNfYywgLWA0QWApCmRhdGF0YWJsZShjb3VudHNfYywKICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICBjYXB0aW9uID0gIlRheG9ub21pYyAgY291bnQgdGFibGUiLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNlYXJjaCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IG5yb3coY291bnRzX2MpKSkgJT4lCiAgZm9ybWF0Q3VycmVuY3koY29sdW1ucyA9IDI6bmNvbChjb3VudHNfYyksCiAgICAgICAgICAgICAgICAgY3VycmVuY3kgPSAiIiwKICAgICAgICAgICAgICAgICBtYXJrID0gIiwiLAogICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDApCmBgYAoKIyMgUmVsYXRpdmUgYWJ1bmRhbmNlICglKSBhdCBDbGFzcyBsZXZlbApgYGB7ciByYV9jLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQpyYV9jIDwtIHJhX2J5X3RheF9yYW5rKGNvdW50cyA9IGNvdW50c19jLAogICAgICAgICAgICAgICAgICAgICAgIHBjdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0ID0gNCkKCmRhdGF0YWJsZShyYV9jLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyhyYV9jKSkpICU+JQogIGZvcm1hdFBlcmNlbnRhZ2UoY29sdW1ucyA9IDI6bmNvbChjb3VudHNfYyksCiAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQpgYGAKCiMjIFBDQSBhdCBDbGFzcyBsZXZlbApgYGB7ciBwY2FfY19wMCwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDZ9CmR0X3BjYSA8LSB0KHJhX2NbLCAyOm5jb2wocmFfYyldKQpjb2xuYW1lcyhkdF9wY2EpIDwtIHJhX2MkQ2xhc3MKCmR0X3BjYV9jIDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoZHRfcGNhKSwKICAgICAgICAgICAgICAgICAgICAgICBkdF9wY2EpCmR0X3BjYV9jIDwtIG1lcmdlKHNtcGwsCiAgICAgICAgICAgICAgICAgIGR0X3BjYV9jLAogICAgICAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQoKIyBLZWVwIG9ubHkgdGhlIENsYXNzIHdpdGggbm9uLXplcm8gY291bnRzCnRtcCA8LSBkdF9wY2FfY1ssIDEwOm5jb2woZHRfcGNhX2MpXQprZWVwX2MgPC0gY29sbmFtZXModG1wKVtjb2xTdW1zKHRtcCkgPiAwXQpkdF9wY2EgPC0gZHRfcGNhWywga2VlcF9jXQoKbTEgPC0gcHJjb21wKGR0X3BjYSwKICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsCiAgICAgICAgICAgICBzY2FsZS4gPSBGQUxTRSkKCnN1bW1hcnkobTEpCgojIFNlbGVjdCBQQy1zIHRvIHBsaW90IChQQzEgJiBQQzIpCmNob2ljZXMgPC0gMToyCgojIEFkZCBtZXRhIGRhdGEKZHQuc2NyIDwtIGRhdGEudGFibGUobTEkeFssIGNob2ljZXNdKQpkdC5zY3IkU2FtcGxlIDwtIHJvd25hbWVzKG0xJHgpCgpkdC5zY3IgPC0gbWVyZ2Uoc21wbCwKICAgICAgICAgICAgICAgIGR0LnNjciwKICAgICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCmR0LnNjcgoKIyBMb2FkaW5ncywgaS5lLiBhcnJvd3MgKGRmLnYpCmR0LnJvdCA8LSBhcy5kYXRhLmZyYW1lKG0xJHJvdGF0aW9uWywgY2hvaWNlc10pCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkKZHQucm90IDwtIGRhdGEudGFibGUoZHQucm90KQpkdC5yb3QKCmR0LmxvYWQgPC0gbWVsdC5kYXRhLnRhYmxlKGR0LnJvdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9ICJmZWF0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMToyLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gInBjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJsb2FkaW5nIikKZHQubG9hZCRmZWF0IDwtIGZhY3RvcihkdC5sb2FkJGZlYXQsCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGR0LmxvYWQkZmVhdCkpCiMgUGxvdCBsb2FkaW5ncwpwMCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LmxvYWQsCiAgICAgICAgICAgICBhZXMoeCA9IGZlYXQsCiAgICAgICAgICAgICAgICAgeSA9IGxvYWRpbmcpKSArCiAgZmFjZXRfd3JhcCh+IHBjLAogICAgICAgICAgICAgbnJvdyA9IDIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBDIExvYWRpbmdzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkKcDAKCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjLjEuMl9sb2FkaW5nc19DbGFzcy50aWZmIiwKICAgICBoZWlnaHQgPSA1LAogICAgIHdpZHRoID0gNiwKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDApCmdyYXBoaWNzLm9mZigpCgpwcmludChwMCkKYGBgCgpgYGB7ciBwY2FfYXhlc19jfQojIEF4aXMgbGFiZWxzCnUuYXhpcy5sYWJzIDwtIHBhc3RlKGNvbG5hbWVzKGR0LnJvdClbMToyXSwgCiAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCptMSRzZGV2W2Nob2ljZXNdXjIvc3VtKG0xJHNkZXZeMikpKQp1LmF4aXMubGFicwpgYGAKCmBgYHtyIGJpcGxvdF9nZW5fYywgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CmNudHIgPC0gZGF0YS50YWJsZShhZ2dyZWdhdGUoeCA9IGR0LnNjciRQQzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KGR0LnNjciRHZW5vdHlwZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gIm1lYW4iKSwKICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZSh4ID0gZHQuc2NyJFBDMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoZHQuc2NyJEdlbm90eXBlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSAibWVhbiIpJHgpCmNvbG5hbWVzKGNudHIpIDwtIGMoIkdlbm90eXBlIiwKICAgICAgICAgICAgICAgICAgICAiUEMxIiwKICAgICAgICAgICAgICAgICAgICAiUEMyIikKCiMgQmFzZWQgb24gRmlndXJlIHAwLCBrZWVwIG9ubHkgYSBmZXcgdmFyaWFibGVzIHdpdGggaGlnaCBsb2FkaW5ncyBpbiBQQzEgYW5kIFBDMi0tLS0KZHQucm90WywgcmF0aW5nOj0gKFBDMSleMiArIChQQzIpXjJdCnNldG9yZGVyKGR0LnJvdCwgLXJhdGluZykKCiMgU2VsZWN0IHRvcCA4CmR0LnJvdCA8LSBkdC5yb3RbMTo4LCBdCgojIHZhci5rZWVwLm5keCA8LSB3aGljaChkdC5yb3QkZmVhdCAlaW4lIGMoLi4uKSkKIyBPciBzZWxlY3QgYWxsCiMgdmFyLmtlZXAubmR4IDwtIDM6bmNvbChkdDEpCiMgVXNlIGR0LnJvdFt2YXIua2VlcC5uZHgsXSBhbmQgZHQucm90JGZlYXRbdmFyLmtlZXAubmR4XQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnJvdCwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHQuc2NyLAogICAgICAgICAgICAgYWVzKGZpbGwgPSBHZW5vdHlwZSwKICAgICAgICAgICAgICAgICBzaGFwZSA9IGZhY3RvcihUaW1lcG9pbnQpKSwKICAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLAogICAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gMC4yKlBDMSwKICAgICAgICAgICAgICAgICAgIHllbmQgPSAwLjIqUEMyKSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEvMiwgJ3BpY2FzJykpLAogICAgICAgICAgICAgICAjIHNpemUgPSAxLCAKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gMC4yMipQQzEsCiAgICAgICAgICAgICAgICB5ID0gMC4yMipQQzIsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGR0LnJvdCRmZWF0KSwKICAgICAgICAgICAgIyBzaXplID0gNSwKICAgICAgICAgICAgaGp1c3QgPSAwLjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMV0pICsKICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkdyb3VwIiwKICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJXaWxkIFR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5yZjIgS08iKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJsdWUiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSAxOjMsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IDIxOjIzKSArCiAgZ2VvbV9sYWJlbChkYXRhID0gY250ciwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIsCiAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5vdHlwZSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSBHZW5vdHlwZSksCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSwKICAgICAgICAgICAgIHNpemUgPSAzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKGd1aWRlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIldpbGQgVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5yZjIgS08iKSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIpKSArCiAgZ2d0aXRsZSgiIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvY2xhc3NfYmlwbG90X2dlbi50aWZmIiwKICAgICBoZWlnaHQgPSA3LAogICAgIHdpZHRoID0gNywKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCgpnZ3Bsb3RseShwMSkKCiMgR2VuZXJpYyBiaXBsb3QKYmlwbG90KG0xKQpgYGAKCiMjIDMuIE9yZGVyCgojIyA0LiBGYW1pbHkKCiMgNS4gR2VudXMKIyMgQ291bnRzIGF0IEdlbnVzIGxldmVsCmBgYHtyIGNvdW50c19nLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KY291bnRzX2cgPC0gY291bnRzX2J5X3RheF9yYW5rKGR0MSA9IG90dSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JfYnkgPSAiR2VudXMiKQpzZXRvcmRlcihjb3VudHNfZywgLWA0QWApCmRhdGF0YWJsZShjb3VudHNfZywKICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICBjYXB0aW9uID0gIlRheG9ub21pYyAgY291bnQgdGFibGUiLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNlYXJjaCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IG5yb3coY291bnRzX2cpKSkgJT4lCiAgZm9ybWF0Q3VycmVuY3koY29sdW1ucyA9IDI6bmNvbChjb3VudHNfZyksCiAgICAgICAgICAgICAgICAgY3VycmVuY3kgPSAiIiwKICAgICAgICAgICAgICAgICBtYXJrID0gIiwiLAogICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDApCmBgYAoKIyMgUmVsYXRpdmUgYWJ1bmRhbmNlICglKSBhdCBHZW51cyBsZXZlbApgYGB7ciByYV9nLCB3YXJuaW5nID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQpyYV9nIDwtIHJhX2J5X3RheF9yYW5rKGNvdW50cyA9IGNvdW50c19nLAogICAgICAgICAgICAgICAgICAgICAgIHBjdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0ID0gNCkKCmRhdGF0YWJsZShyYV9nLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyhyYV9nKSkpICU+JQogIGZvcm1hdFBlcmNlbnRhZ2UoY29sdW1ucyA9IDI6bmNvbChjb3VudHNfZyksCiAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQpgYGAKCiMjIFBDQSBhdCBHZW51cyBsZXZlbApgYGB7ciBwY2FfZ19wMCwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDZ9CmR0X3BjYSA8LSB0KHJhX2dbLCAyOm5jb2wocmFfZyldKQpjb2xuYW1lcyhkdF9wY2EpIDwtIHJhX2ckR2VudXMKCmR0X3BjYV9nIDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoZHRfcGNhKSwKICAgICAgICAgICAgICAgICAgICAgICBkdF9wY2EpCmR0X3BjYV9nIDwtIG1lcmdlKHNtcGwsCiAgICAgICAgICAgICAgICAgIGR0X3BjYV9nLAogICAgICAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQoKIyBLZWVwIG9ubHkgdGhlIEdlbnVzIHdpdGggbm9uLXplcm8gY291bnRzCnRtcCA8LSBkdF9wY2FfZ1ssIDEwOm5jb2woZHRfcGNhX2cpXQprZWVwX2cgPC0gY29sbmFtZXModG1wKVtjb2xTdW1zKHRtcCkgPiAwXQpkdF9wY2EgPC0gZHRfcGNhWywga2VlcF9nXQoKbTEgPC0gcHJjb21wKGR0X3BjYSwKICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsCiAgICAgICAgICAgICBzY2FsZS4gPSBGQUxTRSkKCnN1bW1hcnkobTEpCgojIFNlbGVjdCBQQy1zIHRvIHBsaW90IChQQzEgJiBQQzIpCmNob2ljZXMgPC0gMToyCgojIEFkZCBtZXRhIGRhdGEKZHQuc2NyIDwtIGRhdGEudGFibGUobTEkeFssIGNob2ljZXNdKQpkdC5zY3IkU2FtcGxlIDwtIHJvd25hbWVzKG0xJHgpCgpkdC5zY3IgPC0gbWVyZ2Uoc21wbCwKICAgICAgICAgICAgICAgIGR0LnNjciwKICAgICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCmR0LnNjcgoKIyBMb2FkaW5ncywgaS5lLiBhcnJvd3MgKGRmLnYpCmR0LnJvdCA8LSBhcy5kYXRhLmZyYW1lKG0xJHJvdGF0aW9uWywgY2hvaWNlc10pCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkKZHQucm90IDwtIGRhdGEudGFibGUoZHQucm90KQpkdC5yb3QKCmR0LmxvYWQgPC0gbWVsdC5kYXRhLnRhYmxlKGR0LnJvdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9ICJmZWF0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMToyLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZS5uYW1lID0gInBjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJsb2FkaW5nIikKZHQubG9hZCRmZWF0IDwtIGZhY3RvcihkdC5sb2FkJGZlYXQsCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKGR0LmxvYWQkZmVhdCkpCiMgUGxvdCBsb2FkaW5ncwpwMCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LmxvYWQsCiAgICAgICAgICAgICBhZXMoeCA9IGZlYXQsCiAgICAgICAgICAgICAgICAgeSA9IGxvYWRpbmcpKSArCiAgZmFjZXRfd3JhcCh+IHBjLAogICAgICAgICAgICAgbnJvdyA9IDIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBDIExvYWRpbmdzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkKcDAKCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjLjEuMl9sb2FkaW5nc19nZW51cy50aWZmIiwKICAgICBoZWlnaHQgPSA1LAogICAgIHdpZHRoID0gNiwKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDApCmdyYXBoaWNzLm9mZigpCgpwcmludChwMCkKYGBgCgpgYGB7ciBwY2FfYXhlc19nfQojIEF4aXMgbGFiZWxzCnUuYXhpcy5sYWJzIDwtIHBhc3RlKGNvbG5hbWVzKGR0LnJvdClbMToyXSwgCiAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoJyglMC4xZiUlIGV4cGxhaW5lZCB2YXIuKScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCptMSRzZGV2W2Nob2ljZXNdXjIvc3VtKG0xJHNkZXZeMikpKQp1LmF4aXMubGFicwpgYGAKCmBgYHtyIGJpcGxvdF9nZW5fZywgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CmNudHIgPC0gZGF0YS50YWJsZShhZ2dyZWdhdGUoeCA9IGR0LnNjciRQQzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KGR0LnNjciRHZW5vdHlwZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gIm1lYW4iKSwKICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZSh4ID0gZHQuc2NyJFBDMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoZHQuc2NyJEdlbm90eXBlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSAibWVhbiIpJHgpCmNvbG5hbWVzKGNudHIpIDwtIGMoIkdlbm90eXBlIiwKICAgICAgICAgICAgICAgICAgICAiUEMxIiwKICAgICAgICAgICAgICAgICAgICAiUEMyIikKCiMgQmFzZWQgb24gRmlndXJlIHAwLCBrZWVwIG9ubHkgYSBmZXcgdmFyaWFibGVzIHdpdGggaGlnaCBsb2FkaW5ncyBpbiBQQzEgYW5kIFBDMi0tLS0KZHQucm90WywgcmF0aW5nOj0gKFBDMSleMiArIChQQzIpXjJdCnNldG9yZGVyKGR0LnJvdCwgLXJhdGluZykKCiMgU2VsZWN0IHRvcCA5CmR0LnJvdCA8LSBkdC5yb3RbMTo5LCBdCgojIHZhci5rZWVwLm5keCA8LSB3aGljaChkdC5yb3QkZmVhdCAlaW4lIGMoLi4uKSkKIyBPciBzZWxlY3QgYWxsCiMgdmFyLmtlZXAubmR4IDwtIDM6bmNvbChkdDEpCiMgVXNlIGR0LnJvdFt2YXIua2VlcC5uZHgsXSBhbmQgZHQucm90JGZlYXRbdmFyLmtlZXAubmR4XQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnJvdCwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHQuc2NyLAogICAgICAgICAgICAgYWVzKGZpbGwgPSBHZW5vdHlwZSwKICAgICAgICAgICAgICAgICBzaGFwZSA9IGZhY3RvcihUaW1lcG9pbnQpKSwKICAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLAogICAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gMC4yKlBDMSwKICAgICAgICAgICAgICAgICAgIHllbmQgPSAwLjIqUEMyKSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEvMiwgJ3BpY2FzJykpLAogICAgICAgICAgICAgICAjIHNpemUgPSAxLCAKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gMC4yMipQQzEsCiAgICAgICAgICAgICAgICB5ID0gMC4yMipQQzIsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGR0LnJvdCRmZWF0KSwKICAgICAgICAgICAgIyBzaXplID0gNSwKICAgICAgICAgICAgaGp1c3QgPSAwLjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMV0pICsKICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkdyb3VwIiwKICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJXaWxkIFR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5yZjIgS08iKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJsdWUiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSAxOjMsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IDIxOjIzKSArCiAgZ2VvbV9sYWJlbChkYXRhID0gY250ciwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIsCiAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5vdHlwZSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSBHZW5vdHlwZSksCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSwKICAgICAgICAgICAgIHNpemUgPSAzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKGd1aWRlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIldpbGQgVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5yZjIgS08iKSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIpKSArCiAgZ2d0aXRsZSgiIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvZ2VudXNfYmlwbG90X2dlbi50aWZmIiwKICAgICBoZWlnaHQgPSA3LAogICAgIHdpZHRoID0gNywKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCgpnZ3Bsb3RseShwMSkKCiMgR2VuZXJpYyBiaXBsb3QKYmlwbG90KG0xKQpgYGAKCmBgYHtyIGJpcGxvdF9kaWV0X2csIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSA4fQpjbnRyIDwtIGRhdGEudGFibGUoYWdncmVnYXRlKHggPSBkdC5zY3IkUEMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChkdC5zY3IkRGlldCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gIm1lYW4iKSwKICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZSh4ID0gZHQuc2NyJFBDMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoZHQuc2NyJERpZXQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9ICJtZWFuIikkeCkKY29sbmFtZXMoY250cikgPC0gYygiRGlldCIsCiAgICAgICAgICAgICAgICAgICAgIlBDMSIsCiAgICAgICAgICAgICAgICAgICAgIlBDMiIpCgpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnJvdCwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHQuc2NyLAogICAgICAgICAgICAgYWVzKGZpbGwgPSBEaWV0LAogICAgICAgICAgICAgICAgIHNoYXBlID0gZmFjdG9yKFRpbWVwb2ludCkpLAogICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsCiAgICAgICAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgICAgICAgIHhlbmQgPSAwLjIqUEMxLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IDAuMipQQzIpLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMS8yLCAncGljYXMnKSksCiAgICAgICAgICAgICAgICMgc2l6ZSA9IDEsIAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoYWVzKHggPSAwLjIyKlBDMSwKICAgICAgICAgICAgICAgIHkgPSAwLjIyKlBDMiwKICAgICAgICAgICAgICAgIGxhYmVsID0gZHQucm90JGZlYXQpLAogICAgICAgICAgICAjIHNpemUgPSA1LAogICAgICAgICAgICBoanVzdCA9IDAuNSkgKwogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKwogIHNjYWxlX3lfY29udGludW91cyh1LmF4aXMubGFic1syXSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiR3JvdXAiLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkFJTjkzTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVJVEMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvb2xlZCIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSAxOjMsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IDIxOjIzKSArCiAgZ2VvbV9sYWJlbChkYXRhID0gY250ciwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIsCiAgICAgICAgICAgICAgICAgbGFiZWwgPSBEaWV0LAogICAgICAgICAgICAgICAgIGNvbG91ciA9IERpZXQpLAogICAgICAgICAgICAgYWxwaGEgPSAwLjUsCiAgICAgICAgICAgICBzaXplID0gMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbChndWlkZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJBSU45M00iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRUlUQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvb2xlZCIpLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkgKwogIGdndGl0bGUoIiIpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2dlbnVzX2JpcGxvdF9kaWV0LnRpZmYiLAogICAgIGhlaWdodCA9IDcsCiAgICAgd2lkdGggPSA3LAogICAgIHVuaXRzID0gJ2luJywKICAgICByZXMgPSAzMDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpwcmludChwMikKZ3JhcGhpY3Mub2ZmKCkKCmdncGxvdGx5KHAyKQpgYGAKCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbgpgYGB7ciBpbmZvLGV2YWw9VFJVRX0Kc2Vzc2lvbkluZm8oKQpgYGA=